/* * 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.activities; import android.animation.Animator; import android.animation.ValueAnimator; import android.app.DownloadManager; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.support.v4.view.MenuItemCompat; import android.support.v7.graphics.Palette; import android.support.v7.widget.ShareActionProvider; import android.support.v7.widget.Toolbar; import android.view.Display; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.webkit.MimeTypeMap; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable; import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.musenkishi.paletteloader.PaletteLoader; import com.musenkishi.paletteloader.PaletteRequest; import com.musenkishi.wally.R; import com.musenkishi.wally.anim.interpolator.EaseInOutBezierInterpolator; import com.musenkishi.wally.base.BaseActivity; import com.musenkishi.wally.base.WallyApplication; import com.musenkishi.wally.dataprovider.DataProvider; import com.musenkishi.wally.dataprovider.FileManager; import com.musenkishi.wally.dataprovider.models.DataProviderError; import com.musenkishi.wally.dataprovider.models.SaveImageRequest; import com.musenkishi.wally.fragments.SearchFragment; import com.musenkishi.wally.models.Author; import com.musenkishi.wally.models.Image; import com.musenkishi.wally.models.ImagePage; import com.musenkishi.wally.models.Size; import com.musenkishi.wally.models.Tag; import com.musenkishi.wally.observers.FileReceiver; import com.musenkishi.wally.util.Blur; import com.musenkishi.wally.views.FlowLayout; import com.musenkishi.wally.views.ObservableScrollView; import uk.co.senab.photoview.PhotoViewAttacher; import static com.musenkishi.wally.views.ObservableScrollView.ScrollViewListener; /** * Activity for showing image and any other information about the image. * Created by Musenkishi on 2014-03-05 20:23. */ public class ImageDetailsActivity extends BaseActivity implements Handler.Callback { private static final int MSG_GET_PAGE = 130; private static final int MSG_PAGE_FETCHED = 417892; private static final int MSG_PAGE_ERROR = 417891; private static final int MSG_IMAGE_REQUEST_READY_FOR_SETTING = 987484; private static final int MSG_IMAGE_REQUEST_SAVED = 987483; private static final int MSG_IMAGE_REQUEST_SAVING = 987482; private static final int MSG_SAVE_TO_FILE = 987486; private static final int MSG_RENDER_PALETTE = 987487; private static final int MSG_SET_IMAGE_AND_PALETTE = 987488; private static final int MSG_SCROLL_UP_SCROLLVIEW = 987489; public static final String TAG = "com.musenkishi.wally.ImageDetailsActivity"; private static final String STATE_IMAGE_PAGE = "ImageDetailsActivity.ImagePage"; public static final String INTENT_EXTRA_IMAGE = TAG + ".Intent.Image"; public static final String INTENT_EXTRA_TAG_NAME = TAG + ".Intent.Tag.Name"; public static final int REQUEST_EXTRA_TAG = 13134; private Handler uiHandler; private Handler backgroundHandler; private ObservableScrollView scrollView; private ImageView photoView; private PhotoViewAttacher photoViewAttacher; private ImageButton buttonFullscreen; private ProgressBar loader; private Uri pageUri; private TextView textViewUploader; private TextView textViewUploadDate; private TextView textViewSource; private TextView textViewResolution; private TextView textViewCategory; private TextView textViewRating; private FlowLayout flowLayoutTags; private Button buttonSetAs; private Button buttonSave; private ImagePage imagePage; private ViewGroup imageHolder; private ViewGroup photoLayoutHolder; private int currentHandlerCode; private Palette palette; private ViewGroup toolbar; private ViewGroup specsLayout; private Size imageSize; private boolean isInFullscreen = false; private View detailsViewGroup; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_image_details); setToolbar((Toolbar) findViewById(R.id.toolbar)); if (getToolbar() != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getWindow().setStatusBarColor(Color.TRANSPARENT); getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getToolbar().setPadding(0, getStatusBarHeight(), 0, 0); } getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle(""); } final Intent intent = getIntent(); String action = intent.getAction(); if (Intent.ACTION_VIEW.equals(action)) { pageUri = Uri.parse(intent.getDataString()); if ("wally".equalsIgnoreCase(pageUri.getScheme())){ pageUri = pageUri.buildUpon().scheme("http").build(); } } setupViews(); setupHandlers(); Size size = new Size(16,9); if (intent.hasExtra(INTENT_EXTRA_IMAGE)) { final Image image = intent.getParcelableExtra(INTENT_EXTRA_IMAGE); final Bitmap thumbBitmap = WallyApplication.getBitmapThumb(); if (thumbBitmap != null) { size = fitToWidthAndKeepRatio(image.getWidth(), image.getHeight()); imageSize = size; photoView.getLayoutParams().width = size.getWidth(); photoView.getLayoutParams().height = size.getHeight(); Bitmap blurBitMap; try { blurBitMap = Blur.apply(imageHolder.getContext(), thumbBitmap); } catch (ArrayIndexOutOfBoundsException e) { //Blur couldn't be applied. Show regular thumbnail instead. blurBitMap = thumbBitmap; } photoView.setImageBitmap(blurBitMap); } } setupPaddings(size, false); if (savedInstanceState == null) { getPage(pageUri.toString()); } else if (savedInstanceState.containsKey(STATE_IMAGE_PAGE)){ imagePage = savedInstanceState.getParcelable(STATE_IMAGE_PAGE); } if (imagePage != null) { Message msgObj = uiHandler.obtainMessage(); msgObj.what = MSG_PAGE_FETCHED; msgObj.obj = imagePage; uiHandler.sendMessage(msgObj); } else { getPage(pageUri.toString()); } } public int getStatusBarHeight() { int result = 0; int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = getResources().getDimensionPixelSize(resourceId); } return result; } private void setupPaddings(final Size size, boolean animate) { int animationDuration = animate ? 300 : 0; final int sidePadding = getResources().getDimensionPixelSize(R.dimen.activity_details_scrollview_side_padding); int fabPadding = getResources().getDimensionPixelSize(R.dimen.fab_padding_positive); int minimumAllowedHeight = fabPadding; if (size.getHeight() < minimumAllowedHeight) { size.setHeight(size.getHeight()); ValueAnimator valueAnimator = ValueAnimator.ofInt(photoLayoutHolder.getPaddingTop()); valueAnimator.setInterpolator(new EaseInOutBezierInterpolator()); valueAnimator.setDuration(animationDuration); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { photoLayoutHolder.setPadding( 0, (Integer) valueAnimator.getAnimatedValue(), 0, 0 ); } }); valueAnimator.start(); } else { photoLayoutHolder.setPadding(0, 0, 0, 0 ); } scrollView.setPadding(0, 0, 0, -fabPadding ); specsLayout.setPadding(0, 0, 0, fabPadding); ValueAnimator valueAnimator = ValueAnimator.ofInt(detailsViewGroup.getPaddingTop(), size.getHeight()); valueAnimator.setInterpolator(new EaseInOutBezierInterpolator()); valueAnimator.setDuration(animationDuration); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { detailsViewGroup.setPadding(sidePadding, (Integer) valueAnimator.getAnimatedValue(), sidePadding, detailsViewGroup.getPaddingBottom()); } }); valueAnimator.start(); } @Override protected void onSaveInstanceState(Bundle outState) { if (imagePage != null) { outState.putParcelable(STATE_IMAGE_PAGE, imagePage); } super.onSaveInstanceState(outState); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.image_details, menu); MenuItem shareMenuItem = menu.findItem(R.id.action_share); if (shareMenuItem != null) { ShareActionProvider shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareMenuItem); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); shareIntent.putExtra(Intent.EXTRA_TEXT, pageUri.toString()); shareActionProvider.setShareIntent(shareIntent); shareMenuItem.setIcon(R.drawable.ic_action_share); } return super.onCreateOptionsMenu(menu); } @Override public boolean onSupportNavigateUp() { finish(); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.action_share: return false; case R.id.action_open: Intent browserIntent = new Intent(Intent.ACTION_VIEW, pageUri); startActivity(browserIntent); break; } return super.onOptionsItemSelected(item); } @Override protected void onPause() { Drawable heart = getResources().getDrawable(R.drawable.ic_action_saved); heart.clearColorFilter(); super.onPause(); } @Override protected void onDestroy() { Glide.clear(photoView); backgroundHandler.removeCallbacksAndMessages(null); uiHandler.removeCallbacksAndMessages(null); backgroundHandler.getLooper().quit(); super.onDestroy(); } private void setupViews() { scrollView = (ObservableScrollView) findViewById(R.id.image_details_scrollview); imageHolder = (ViewGroup) findViewById(R.id.image_details_imageview_holder); photoView = (ImageView) findViewById(R.id.image_details_imageview); buttonFullscreen = (ImageButton) findViewById(R.id.image_details_button_fullscreen); loader = (ProgressBar) findViewById(R.id.image_details_loader); textViewUploader = (TextView) findViewById(R.id.image_details_uploader); textViewUploadDate = (TextView) findViewById(R.id.image_details_upload_date); textViewSource = (TextView) findViewById(R.id.image_details_source); textViewResolution = (TextView) findViewById(R.id.image_details_resolution); textViewCategory = (TextView) findViewById(R.id.image_details_category); textViewRating = (TextView) findViewById(R.id.image_details_rating); flowLayoutTags = (FlowLayout) findViewById(R.id.image_details_tags_layout); buttonSetAs = (Button) findViewById(R.id.toolbar_set_as); buttonSave = (Button) findViewById(R.id.toolbar_save); toolbar = (ViewGroup) findViewById(R.id.image_details_toolbar); photoLayoutHolder = (ViewGroup) findViewById(R.id.image_details_photo_layout_holder); specsLayout = (ViewGroup) findViewById(R.id.image_details_specs); detailsViewGroup = findViewById(R.id.image_details_layout); specsLayout.setAlpha(0.0f); int sidePadding = getResources().getDimensionPixelSize(R.dimen.activity_details_scrollview_side_padding); int fabPadding = getResources().getDimensionPixelSize(R.dimen.fab_padding_positive); scrollView.setPadding(0, 0, 0, -fabPadding); specsLayout.setPadding(0, 0, 0, fabPadding); photoLayoutHolder.setPadding(0, 0, 0, 0); detailsViewGroup.setPadding( sidePadding, detailsViewGroup.getPaddingTop(), sidePadding, detailsViewGroup.getPaddingBottom() ); } @Override public void onBackPressed() { if (isInFullscreen()) { toggleZoomImage(); } else { super.onBackPressed(); } } private Size fitToWidthAndKeepRatio(int width, int height) { WindowManager win = getWindowManager(); Display d = win.getDefaultDisplay(); int displayWidth = d.getWidth(); // Width of the actual device int fittedHeight = height; int fittedWidth = width; fittedHeight = displayWidth * fittedHeight / fittedWidth; fittedWidth = displayWidth; return new Size(fittedWidth, fittedHeight); } private void enableParallaxEffect(ObservableScrollView scrollView, final View parallaxingView) { scrollView.setScrollViewListener(new ScrollViewListener() { @Override public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) { WindowManager win = getWindowManager(); Display d = win.getDefaultDisplay(); int displayHeight = d.getHeight(); // Height of the actual device if (imageSize.getHeight() > displayHeight && photoViewAttacher != null) { float[] values = new float[9]; photoViewAttacher.getDrawMatrix().getValues(values); float imageHeight = imageSize.getHeight(); float diff = imageHeight/displayHeight; if (y > oldy) { diff = -diff; } photoViewAttacher.onDrag(0, diff); } else { float pY = -(y / 3.0f); parallaxingView.setTranslationY(pY); } } }); } private void saveImage(boolean notifyUser) { if (notifyUser) { uiHandler.sendEmptyMessage(MSG_IMAGE_REQUEST_SAVING); } Message msgObj = backgroundHandler.obtainMessage(); msgObj.what = MSG_SAVE_TO_FILE; msgObj.arg1 = MSG_IMAGE_REQUEST_SAVED; backgroundHandler.sendMessage(msgObj); } private void setImageAsWallpaperPicker(Uri path) { Intent intent = new Intent(Intent.ACTION_ATTACH_DATA); intent.setType("image/*"); MimeTypeMap map = MimeTypeMap.getSingleton(); String mimeType = map.getMimeTypeFromExtension("png"); intent.setDataAndType(path, 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 getPage(String url) { Message msgGetPage = backgroundHandler.obtainMessage(); msgGetPage.what = MSG_GET_PAGE; msgGetPage.obj = url; backgroundHandler.sendMessage(msgGetPage); } private void setupHandlers() { HandlerThread handlerThread = new HandlerThread("background"); handlerThread.start(); backgroundHandler = new Handler(handlerThread.getLooper(), this); uiHandler = new Handler(getMainLooper(), this); } private void renderTags(Bitmap bitmap) { if (this.palette == null && flowLayoutTags.getChildCount() > 0) { for (int i = 0; i < flowLayoutTags.getChildCount(); i++) { View tagView = flowLayoutTags.getChildAt(i); TextView tagTextView = (TextView) tagView.findViewById(R.id.tag_item_text); PaletteLoader.with(this, imagePage.imagePath().toString()) .load(bitmap) .setPaletteRequest(new PaletteRequest( PaletteRequest.SwatchType.REGULAR_MUTED, PaletteRequest.SwatchColor.BACKGROUND)) .into(tagTextView); } } } private void renderColors(Bitmap bitmap) { //Could already be rendered b.c. duplicate callback by Glide. if (this.palette == null) { PaletteLoader.with(this, imagePage.imagePath().toString()) .load(bitmap) .setPaletteRequest(new PaletteRequest( PaletteRequest.SwatchType.DARK_MUTED, PaletteRequest.SwatchColor.BACKGROUND)) .setListener(new PaletteLoader.OnPaletteRenderedListener() { @Override public void onRendered(Palette palette) { setColors(palette); } }) .into(findViewById(R.id.image_details_root)); } } private void setColors(Palette palette){ this.palette = palette; hideLoader(); Palette.Swatch swatch = PaletteRequest.getBestSwatch(palette, palette.getDarkMutedSwatch()); if (swatch != null) { photoLayoutHolder.setBackgroundColor(swatch.getRgb()); Drawable floatingButtonBackground = getResources() .getDrawable(R.drawable.floating_action_button); Drawable floatingButtonIcon = getResources().getDrawable(R.drawable.ic_mask_fullscreen); Palette.Swatch fabSwatch = PaletteRequest.getBestSwatch(palette, palette.getVibrantSwatch()); if (fabSwatch != null) { floatingButtonBackground.setColorFilter(fabSwatch.getRgb(), PorterDuff.Mode.MULTIPLY); floatingButtonIcon.setColorFilter(fabSwatch.getBodyTextColor(), PorterDuff.Mode.MULTIPLY); } buttonFullscreen.setBackgroundDrawable(floatingButtonBackground); buttonFullscreen.setImageDrawable(floatingButtonIcon); buttonFullscreen.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { toggleZoomImage(); } }); toolbar.setBackgroundColor(swatch.getRgb()); buttonSetAs.setTextColor(swatch.getBodyTextColor()); buttonSave.setTextColor(swatch.getBodyTextColor()); setToolbarClickListeners(); animateToolbar(View.VISIBLE); } } /** * Animations animations animations. * @param visibility if VISIBLE, expands toolbar. */ private void animateToolbar(int visibility) { float from; float to; int toolbarOffset; int fabOffset; if (visibility == View.VISIBLE) { from = 0.0f; to = 1.0f; fabOffset = 200; toolbarOffset = 0; } else { from = 1.0f; to = 0.0f; fabOffset = 0; toolbarOffset = 200; } buttonFullscreen.animate() .scaleX(to) .scaleY(to) .setDuration(400) .setStartDelay(fabOffset) .setInterpolator(new EaseInOutBezierInterpolator()) .setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { buttonFullscreen.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(Animator animator) { } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }) .start(); int toolbarFrom; int toolbarTo; if (from > 0.0f) { toolbarFrom = getResources().getDimensionPixelSize(R.dimen.details_toolbar_height); toolbarTo = 0; } else { toolbarFrom = 0; toolbarTo = getResources().getDimensionPixelSize(R.dimen.details_toolbar_height); } ValueAnimator valueAnimator = ValueAnimator.ofInt(toolbarFrom, toolbarTo); valueAnimator.setDuration(400); valueAnimator.setStartDelay(toolbarOffset); valueAnimator.setInterpolator(new EaseInOutBezierInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int val = (Integer) valueAnimator.getAnimatedValue(); RelativeLayout.LayoutParams toolbarParams = (RelativeLayout.LayoutParams) toolbar.getLayoutParams(); toolbarParams.height = val; toolbar.setLayoutParams(toolbarParams); } }); valueAnimator.start(); } private void setToolbarClickListeners() { buttonSetAs.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msgObj = backgroundHandler.obtainMessage(); msgObj.what = MSG_SAVE_TO_FILE; msgObj.arg1 = MSG_IMAGE_REQUEST_READY_FOR_SETTING; backgroundHandler.sendMessage(msgObj); } }); updateSaveButton(); } private void updateSaveButton() { if (imagePage != null) { FileManager fileManager = new FileManager(); boolean imageExists = fileManager.fileExists(imagePage.imageId()); if (imageExists) { buttonSave.setClickable(false); buttonSave.setText(R.string.saved); buttonSave.setAlpha(0.5f); } else { if (!buttonSave.isClickable()){ buttonSave.setClickable(true); buttonSave.setText(R.string.action_save); } buttonSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { v.setClickable(false); saveImage(true); } }); } } } private void saveToFile(final int handlerCode) { currentHandlerCode = handlerCode; SaveImageRequest saveImageRequest = WallyApplication .getDataProviderInstance() .downloadImageIfNeeded( imagePage.imagePath(), pageUri.getLastPathSegment(), getResources().getString(R.string.notification_title_image_saving)); if (saveImageRequest.getDownloadID() != null){ WallyApplication.getDownloadIDs().put(saveImageRequest.getDownloadID(), pageUri.getLastPathSegment()); } else { handleSavedImageData(saveImageRequest.getFilePath()); } } @Override protected void handleReceivedIntent(Context context, Intent intent) { long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0L); if (WallyApplication.getDownloadIDs().containsKey(id)){ WallyApplication.getDownloadIDs().remove(id); updateSaveButton(); if (palette != null && palette.getVibrantSwatch() != null) { startHeartPopoutAnimation(buttonSave, palette.getVibrantSwatch().getBodyTextColor()); } else { startHeartPopoutAnimation(buttonSave, Color.WHITE); } String filename = pageUri.getLastPathSegment(); handleSavedImageData(WallyApplication.getDataProviderInstance().getFilePath(filename)); } } private void handleSavedImageData(Uri filePath) { if (filePath != null && filePath.getPath() != null) { Message msgObj = uiHandler.obtainMessage(); msgObj.what = currentHandlerCode; msgObj.obj = filePath; uiHandler.sendMessage(msgObj); MediaScannerConnection.scanFile(getApplicationContext(), new String[]{filePath.getPath()}, null, new MediaScannerConnection.MediaScannerConnectionClient() { @Override public void onMediaScannerConnected() { } @Override public void onScanCompleted(String path, Uri uri) { getApplication().sendBroadcast(new Intent(FileReceiver.GET_FILES)); } } ); } } private void showLoader() { loader.animate().alpha(1.0f).setDuration(300).start(); } private void hideLoader() { loader.animate().alpha(0.0f).setDuration(300).start(); } /** * Returns true if fullscreen mode is currently active. */ private boolean isInFullscreen() { return isInFullscreen; } /** * Animations animations animations. */ private void toggleZoomImage() { int animationDuration = 400; if (isInFullscreen()){ scrollView.smoothScrollTo(0, (Integer) scrollView.getTag()); if (photoViewAttacher != null) { photoViewAttacher.cleanup(); photoViewAttacher = null; photoView.setScaleType(ImageView.ScaleType.CENTER_CROP); } } else { scrollView.setTag(scrollView.getScrollY()); scrollView.smoothScrollTo(0, 0); if (photoViewAttacher == null) { photoViewAttacher = new PhotoViewAttacher(photoView); photoViewAttacher.setZoomable(true); photoViewAttacher.setScaleType(ImageView.ScaleType.CENTER_CROP); } } if (getSupportActionBar() != null) { getToolbar().animate() .translationY(isInFullscreen() ? 0.0f : -getToolbar().getMeasuredHeight()) .alpha(isInFullscreen() ? 1.0f : 0.0f) .setDuration(500) .setInterpolator(new EaseInOutBezierInterpolator()) .start(); } findViewById(R.id.image_details_protective_shadow).animate() .alpha(isInFullscreen() ? 1.0f : 0.0f) .setDuration(500) .setInterpolator(new EaseInOutBezierInterpolator()) .start(); int minimumAllowedHeight = getToolbar().getMeasuredHeight() + getResources().getDimensionPixelSize(R.dimen.fab_padding_positive); if (imageSize.getHeight() < minimumAllowedHeight) { int topFrom; int topTo; if (isInFullscreen()) { topFrom = 0; topTo = getToolbar().getMeasuredHeight(); } else { topFrom = photoLayoutHolder.getPaddingTop(); topTo = 0; } ValueAnimator topValueAnimator = ValueAnimator.ofInt(topFrom, topTo); topValueAnimator.setDuration(animationDuration); topValueAnimator.setInterpolator(new EaseInOutBezierInterpolator()); topValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int val = (Integer) valueAnimator.getAnimatedValue(); photoLayoutHolder.setPadding( photoLayoutHolder.getPaddingLeft(), val, photoLayoutHolder.getPaddingRight(), photoLayoutHolder.getPaddingBottom() ); } }); topValueAnimator.start(); } if (photoLayoutHolder.getTranslationY() != 0.0f) { photoLayoutHolder.animate() .translationY(0.0f) .setInterpolator(new EaseInOutBezierInterpolator()) .setDuration(animationDuration) .start(); } WindowManager win = getWindowManager(); Display d = win.getDefaultDisplay(); int from = photoView.getMeasuredHeight(); int to = isInFullscreen() ? imageSize.getHeight() : d.getHeight(); ValueAnimator valueAnimator = ValueAnimator.ofInt(from, to); valueAnimator.setDuration(animationDuration); valueAnimator.setInterpolator(new EaseInOutBezierInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int val = (Integer) valueAnimator.getAnimatedValue(); RelativeLayout.LayoutParams toolbarParams = (RelativeLayout.LayoutParams) photoView.getLayoutParams(); toolbarParams.height = val; photoView.setLayoutParams(toolbarParams); } }); valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) {} @Override public void onAnimationEnd(Animator animator) { if (photoViewAttacher != null) { photoViewAttacher.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() { @Override public void onPhotoTap(View view, float v, float v2) { toggleZoomImage(); } }); } } @Override public void onAnimationCancel(Animator animator) {} @Override public void onAnimationRepeat(Animator animator) {} }); valueAnimator.start(); int scrollTo = isInFullscreen() ? 0 : d.getHeight(); scrollView.animate() .y(scrollTo) .setDuration(animationDuration) .setInterpolator(new EaseInOutBezierInterpolator()) .start(); isInFullscreen = !isInFullscreen; } private void scrollUpToolbarIfNeeded() { Display thisDisplay = getWindowManager().getDefaultDisplay(); int screenHeight = thisDisplay.getHeight(); int emptySpace = detailsViewGroup.getPaddingTop(); int targetHeight = emptySpace - ((screenHeight/3)*2); int navBarHeight = 0; if (imageSize.getHeight() > (screenHeight - navBarHeight)) { Message msgObj = uiHandler.obtainMessage(); msgObj.what = MSG_SCROLL_UP_SCROLLVIEW; msgObj.arg1 = targetHeight; uiHandler.sendMessageDelayed(msgObj, 500); } } @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_GET_PAGE: String url = (String) msg.obj; if (url != null) { WallyApplication.getDataProviderInstance().getPageData( url, new DataProvider.OnPageReceivedListener() { @Override public void onPageReceived(ImagePage imagePage) { Message msgObj = uiHandler.obtainMessage(); msgObj.what = MSG_PAGE_FETCHED; msgObj.obj = imagePage; uiHandler.sendMessage(msgObj); } @Override public void onError(DataProviderError error) { Message msgObj = uiHandler.obtainMessage(); msgObj.what = MSG_PAGE_ERROR; msgObj.obj = error; uiHandler.sendMessage(msgObj); } }); } break; case MSG_SAVE_TO_FILE: int what = msg.arg1; saveToFile(what); break; case MSG_PAGE_FETCHED: imagePage = (ImagePage) msg.obj; if (imagePage != null) { textViewUploader.setText(imagePage.uploader()); textViewUploadDate.setText(imagePage.uploadDate()); textViewSource.setText(imagePage.author().name()); if (imagePage.author().page() != Uri.EMPTY) { textViewSource.setTextColor(getResources() .getColor(R.color.Holo_Blue_Dark) ); textViewSource.setTag(imagePage.author()); textViewSource.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Author author = (Author) v.getTag(); if (author.page() != Uri.EMPTY) { Intent browserIntent = new Intent( Intent.ACTION_VIEW, author.page() ); startActivity(browserIntent); } } }); } textViewResolution.setText(imagePage.resolution()); textViewCategory.setText(imagePage.category()); textViewRating.setText(imagePage.rating()); final String imageUrl = imagePage.imagePath().toString(); if (imagePage.tags().size() > 0) { flowLayoutTags.removeAllViews(); for (final Tag tag : imagePage.tags()) { View tagView = getLayoutInflater().inflate(R.layout.view_tag_item, flowLayoutTags, false); TextView tagTextView = (TextView) tagView.findViewById(R.id.tag_item_text); tagTextView.setText(tag.name()); flowLayoutTags.addView(tagView); tagTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { WallyApplication.getSearchFragmentMessages().put(SearchFragment.EXTRA_MESSAGE_TAG, tag.name()); Intent intent = new Intent(); setResult(RESULT_OK, intent); ImageDetailsActivity.this.finish(); } }); } } else { findViewById(R.id.image_details_tags_title).setVisibility(View.GONE); flowLayoutTags.setVisibility(View.GONE); } Glide.with(getApplicationContext()) .load(imageUrl) .placeholder(photoView.getDrawable()) .fitCenter() .listener(new RequestListener<String, GlideDrawable>() { @Override public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) { hideLoader(); //TODO: maybe show a retry button? return false; } @Override public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { photoView.setScaleType(ImageView.ScaleType.CENTER_CROP); renderTags( ((GlideBitmapDrawable) resource.getCurrent()) .getBitmap() ); renderColors( ((GlideBitmapDrawable) resource.getCurrent()) .getBitmap() ); photoView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { toggleZoomImage(); } }); hideLoader(); Size size = fitToWidthAndKeepRatio( imagePage.getImageWidth(), imagePage.getImageHeight() ); imageSize = size; setupPaddings(size, true); scrollUpToolbarIfNeeded(); return false; } }) .into(photoView); specsLayout.setAlpha(1.0f); specsLayout.scheduleLayoutAnimation(); enableParallaxEffect(scrollView, photoLayoutHolder); } break; case MSG_PAGE_ERROR: DataProviderError dataProviderError = (DataProviderError) msg.obj; if (dataProviderError != null) { Toast.makeText(ImageDetailsActivity.this, dataProviderError.getHttpStatusCode() + ": " + dataProviderError.getMessage(), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ImageDetailsActivity.this, getString(R.string.toast_error_default), Toast.LENGTH_SHORT).show(); } break; case MSG_IMAGE_REQUEST_READY_FOR_SETTING: Uri savedImageDataForWallpaper = (Uri) msg.obj; if (savedImageDataForWallpaper != null) { setImageAsWallpaperPicker(savedImageDataForWallpaper); } break; case MSG_IMAGE_REQUEST_SAVED: updateSaveButton(); break; case MSG_IMAGE_REQUEST_SAVING: if (buttonSave != null) { buttonSave.setText(getString(R.string.saving)); buttonSave.setAlpha(0.50f); } break; case MSG_RENDER_PALETTE: Bitmap bitmap1 = (Bitmap) msg.obj; Palette palette = Palette.generate(bitmap1); Message msgObj = uiHandler.obtainMessage(); msgObj.what = MSG_SET_IMAGE_AND_PALETTE; msgObj.obj = palette; uiHandler.sendMessage(msgObj); break; case MSG_SET_IMAGE_AND_PALETTE: Palette renderedPalette = (Palette) msg.obj; setColors(renderedPalette); break; case MSG_SCROLL_UP_SCROLLVIEW: int targetScroll = msg.arg1; scrollView.smoothScrollTo(0, targetScroll); break; } return false; } }