Android Open Source - wally Image Details Activity






From Project

Back to project page wally.

License

The source code is released under:

Apache License

If you think the Android project wally listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2014 Freddie (Musenkishi) Lust-Hed
 */*from  w w  w  . j  av a2s .  c om*/
 * 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.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.models.Author;
import com.musenkishi.wally.models.Image;
import com.musenkishi.wally.models.ImagePage;
import com.musenkishi.wally.models.Size;
import com.musenkishi.wally.observers.FileChangeReceiver;
import com.musenkishi.wally.util.Blur;
import com.musenkishi.wally.util.PaletteRequest;
import com.musenkishi.wally.views.ObservableScrollView;

import uk.co.senab.photoview.PhotoView;
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";

    private Handler uiHandler;
    private Handler backgroundHandler;

    private ObservableScrollView scrollView;
    private PhotoView photoView;
    private PhotoViewAttacher photoViewAttacher;
    private ImageButton buttonFullscreen;
    private ProgressBar loader;
    private Uri pageUri;
    private ShareActionProvider shareActionProvider;
    private TextView textViewUploader;
    private TextView textViewUploadDate;
    private TextView textViewSource;
    private TextView textViewResolution;
    private TextView textViewCategory;
    private TextView textViewRating;
    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());

                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;

        photoView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        photoViewAttacher.setScaleType(ImageView.ScaleType.CENTER_CROP);

        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) 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 = (PhotoView) 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);
        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()
        );

        photoViewAttacher = new PhotoViewAttacher(photoView);
        photoViewAttacher.setZoomable(false);
        photoViewAttacher.setScaleType(ImageView.ScaleType.FIT_XY);
    }

    @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) {
                    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 renderColors(Bitmap bitmap) {
        Message msgObj = backgroundHandler.obtainMessage();
        msgObj.what = MSG_RENDER_PALETTE;
        msgObj.obj = bitmap;
        msgObj.arg1 = MSG_IMAGE_REQUEST_SAVED;
        backgroundHandler.sendMessage(msgObj);
    }

    private void setColors(Palette palette){
        this.palette = palette;
        hideLoader();

        Palette.Swatch swatch = PaletteRequest.getBestSwatch(palette, palette.getDarkMutedSwatch());
        if (swatch != null) {
            photoLayoutHolder.setBackgroundColor(swatch.getRgb());
            findViewById(R.id.image_details_root).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(FileChangeReceiver.FILES_CHANGED));
                        }
                    }
            );
        }
    }

    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());
            photoViewAttacher.setScale(1.0f, true);
        } else {
            scrollView.setTag(scrollView.getScrollY());
            scrollView.smoothScrollTo(0, 0);
        }

        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) {
                photoViewAttacher.setZoomable(true);
                photoView.setZoomable(true);
                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();

                    Glide.with(getApplicationContext())
                            .load(imageUrl)
                            .placeholder(photoViewAttacher.getImageView().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);
                                    photoViewAttacher.setScaleType(ImageView.ScaleType.CENTER_CROP);

                                    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);

                                    enableParallaxEffect(scrollView, photoLayoutHolder);

                                    scrollUpToolbarIfNeeded();

                                    return false;
                                }
                            })
                            .into(photoView);

                    specsLayout.setAlpha(1.0f);
                    specsLayout.scheduleLayoutAnimation();

                }
                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 colorScheme = Palette.generate(bitmap1);

                Message msgObj = uiHandler.obtainMessage();
                msgObj.what = MSG_SET_IMAGE_AND_PALETTE;
                msgObj.obj = colorScheme;
                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;
    }
}




Java Source Code List

com.musenkishi.wally.activities.ImageDetailsActivity.java
com.musenkishi.wally.activities.MainActivity.java
com.musenkishi.wally.adapters.RecyclerImagesAdapter.java
com.musenkishi.wally.adapters.RecyclerSavedImagesAdapter.java
com.musenkishi.wally.adapters.SmartFragmentPagerAdapter.java
com.musenkishi.wally.adapters.SmartFragmentStatePagerAdapter.java
com.musenkishi.wally.anim.BaseItemAnimator.java
com.musenkishi.wally.anim.ScaleInOutItemAnimator.java
com.musenkishi.wally.anim.interpolator.EaseInOutBezierInterpolator.java
com.musenkishi.wally.anim.interpolator.FastOutLinearInInterpolator.java
com.musenkishi.wally.anim.interpolator.FastOutSlowInInterpolator.java
com.musenkishi.wally.anim.interpolator.LinearOutSlowInInterpolator.java
com.musenkishi.wally.base.BaseActivity.java
com.musenkishi.wally.base.BaseFragment.java
com.musenkishi.wally.base.GridFragment.java
com.musenkishi.wally.base.WallyApplication.java
com.musenkishi.wally.dataprovider.DataProvider.java
com.musenkishi.wally.dataprovider.FileManager.java
com.musenkishi.wally.dataprovider.NetworkDataProvider.java
com.musenkishi.wally.dataprovider.SharedPreferencesDataProvider.java
com.musenkishi.wally.dataprovider.models.DataProviderError.java
com.musenkishi.wally.dataprovider.models.SaveImageRequest.java
com.musenkishi.wally.dataprovider.okhttp.OkHttpStreamFetcher.java
com.musenkishi.wally.dataprovider.okhttp.OkHttpUrlLoader.java
com.musenkishi.wally.dataprovider.util.Parser.java
com.musenkishi.wally.fragments.CustomResolutionDialogFragment.java
com.musenkishi.wally.fragments.FilterDialogFragment.java
com.musenkishi.wally.fragments.ImageZoomFragment.java
com.musenkishi.wally.fragments.LatestFragment.java
com.musenkishi.wally.fragments.MaterialDialogFragment.java
com.musenkishi.wally.fragments.RandomImagesFragment.java
com.musenkishi.wally.fragments.SavedImagesFragment.java
com.musenkishi.wally.fragments.SearchFragment.java
com.musenkishi.wally.fragments.ToplistFragment.java
com.musenkishi.wally.models.Author.java
com.musenkishi.wally.models.ExceptionReporter.java
com.musenkishi.wally.models.Filter.java
com.musenkishi.wally.models.ImagePage.java
com.musenkishi.wally.models.Image.java
com.musenkishi.wally.models.ListFilterGroup.java
com.musenkishi.wally.models.Rating.java
com.musenkishi.wally.models.SavedImageData.java
com.musenkishi.wally.models.Size.java
com.musenkishi.wally.models.Tag.java
com.musenkishi.wally.models.filters.FilterAspectRatioKeys.java
com.musenkishi.wally.models.filters.FilterBoardsKeys.java
com.musenkishi.wally.models.filters.FilterBoards.java
com.musenkishi.wally.models.filters.FilterGroup.java
com.musenkishi.wally.models.filters.FilterGroupsStructure.java
com.musenkishi.wally.models.filters.FilterPurityKeys.java
com.musenkishi.wally.models.filters.FilterPurity.java
com.musenkishi.wally.models.filters.FilterResOptKeys.java
com.musenkishi.wally.models.filters.FilterResOpt.java
com.musenkishi.wally.models.filters.FilterResolutionKeys.java
com.musenkishi.wally.models.filters.FilterTimeSpanKeys.java
com.musenkishi.wally.muzei.WallyArtSource.java
com.musenkishi.wally.notification.NotificationProvider.java
com.musenkishi.wally.observers.FileChangeReceiver.java
com.musenkishi.wally.observers.FiltersChangeReceiver.java
com.musenkishi.wally.util.Blur.java
com.musenkishi.wally.util.PaletteLoader.java
com.musenkishi.wally.util.PaletteRequest.java
com.musenkishi.wally.util.SparseBooleanArrayParcelable.java
com.musenkishi.wally.util.TextClickableSpan.java
com.musenkishi.wally.util.TextLinkBuilder.java
com.musenkishi.wally.util.TypefaceSpan.java
com.musenkishi.wally.views.AutoGridView.java
com.musenkishi.wally.views.GridRecyclerView.java
com.musenkishi.wally.views.ObservableScrollView.java
com.musenkishi.wally.views.TabBarView.java
com.musenkishi.wally.views.TabView.java
com.musenkishi.wally.views.swipeclearlayout.SwipeClearLayout.java
net.margaritov.preference.colorpicker.dialog.ColorPickerDialogFragment.java
net.margaritov.preference.colorpicker.drawable.AlphaPatternDrawable.java
net.margaritov.preference.colorpicker.preference.ColorPickerPreference.java
net.margaritov.preference.colorpicker.view.ColorPanelView.java
net.margaritov.preference.colorpicker.view.ColorPickerView.java
nl.codesoup.cubicbezier.CubicBezierInterpolator.java