ooo.oxo.mr.ViewerActivity.java Source code

Java tutorial

Introduction

Here is the source code for ooo.oxo.mr.ViewerActivity.java

Source

/*
 * Mr.Mantou - On the importance of taste
 * Copyright (C) 2015-2016  XiNGRZ <xxx@oxo.ooo>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package ooo.oxo.mr;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.WallpaperManager;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.databinding.ObservableArrayList;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.SharedElementCallback;
import android.support.v4.content.FileProvider;
import android.support.v4.view.ViewPager;
import android.transition.Transition;
import android.util.Log;
import android.view.View;

import com.bumptech.glide.Glide;
import com.jakewharton.rxbinding.view.RxMenuItem;
import com.tbruyelle.rxpermissions.RxPermissions;
import com.trello.rxlifecycle.components.support.RxAppCompatActivity;
import com.umeng.analytics.MobclickAgent;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import ooo.oxo.library.widget.PullBackLayout;
import ooo.oxo.mr.databinding.ViewerActivityBinding;
import ooo.oxo.mr.model.Image;
import ooo.oxo.mr.rx.RxFiles;
import ooo.oxo.mr.rx.RxGlide;
import ooo.oxo.mr.util.ImmersiveUtil;
import ooo.oxo.mr.util.InOutAnimationUtils;
import ooo.oxo.mr.util.ObservableListPagerAdapterCallback;
import ooo.oxo.mr.util.SimpleTransitionListener;
import ooo.oxo.mr.util.ToastUtil;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class ViewerActivity extends RxAppCompatActivity implements PullBackLayout.Callback {

    private static final String TAG = "ViewerActivity";

    private static final String AUTHORITY_IMAGES = BuildConfig.APPLICATION_ID + ".images";

    private final ObservableArrayList<Image> images = MrSharedState.getInstance().getImages();

    private ViewerActivityBinding binding;

    private Adapter adapter;

    private ObservableListPagerAdapterCallback listener;

    private ColorDrawable background;

    private static String makeFileName(Image image) {
        return String.format(Locale.US, "%d.%s", image.getCreatedAt().getTime(), image.getType());
    }

    private Observable<Void> menuItemClicks(@IdRes int id) {
        return RxMenuItem.clicks(binding.toolbar.getMenu().findItem(id));
    }

    private Observable<File> ensureExternalDirectory(String name) {
        return RxFiles.mkdirsIfNotExists(new File(Environment.getExternalStorageDirectory(), name));
    }

    private Observable<File> download(Image image) {
        return RxGlide.download(Glide.with(this), image.getUrl());
    }

    private Observable<File> save(Image image, File destination) {
        return download(image).flatMap(tmp -> RxFiles.copy(tmp, destination));
    }

    private Observable<File> saveIfNeeded(Image image) {
        return ensureExternalDirectory("Mr.Mantou").map(directory -> new File(directory, makeFileName(image)))
                .flatMap(file -> file.exists() ? Observable.just(file) : save(image, file));
    }

    private Observable.Transformer<Void, Void> ensurePermissions(@NonNull String... permissions) {
        return source -> source.compose(RxPermissions.getInstance(this).ensure(permissions)).filter(granted -> {
            if (granted) {
                return true;
            } else {
                ToastUtil.shorts(this, R.string.permission_required);
                return false;
            }
        }).map(granted -> null);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.viewer_activity);

        setTitle(null);

        binding.toolbar.setNavigationOnClickListener(v -> supportFinishAfterTransition());
        binding.toolbar.inflateMenu(R.menu.viewer);

        binding.puller.setCallback(this);

        supportPostponeEnterTransition();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().getEnterTransition().addListener(new SimpleTransitionListener() {
                @Override
                @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                public void onTransitionEnd(Transition transition) {
                    getWindow().getEnterTransition().removeListener(this);
                    fadeIn();
                }
            });
        } else {
            fadeIn();
        }

        background = new ColorDrawable(Color.BLACK);
        binding.getRoot().setBackground(background);

        adapter = new Adapter();

        binding.pager.setAdapter(adapter);
        binding.pager.setCurrentItem(getIntent().getIntExtra("index", 0));
        binding.pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageScrollStateChanged(int state) {
                if (state == ViewPager.SCROLL_STATE_DRAGGING) {
                    fadeOut();
                }
            }
        });

        listener = new ObservableListPagerAdapterCallback(adapter);
        images.addOnListChangedCallback(listener);

        setEnterSharedElementCallback(new SharedElementCallback() {
            @Override
            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
                Image image = images.get(binding.pager.getCurrentItem());
                sharedElements.clear();
                sharedElements.put(String.format("%s.image", image.getObjectId()), getCurrent().getSharedElement());
            }
        });

        menuItemClicks(R.id.share).compose(bindToLifecycle())
                .compose(ensurePermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE))
                .map(avoid -> getCurrentImage())
                .doOnNext(image -> MobclickAgent.onEvent(this, "share", image.getObjectId()))
                .observeOn(Schedulers.io()).flatMap(this::saveIfNeeded).observeOn(AndroidSchedulers.mainThread())
                .doOnNext(this::notifyMediaScanning).map(Uri::fromFile).retry().subscribe(uri -> {
                    final Intent intent = new Intent(Intent.ACTION_SEND);
                    intent.setType("image/jpeg");
                    intent.putExtra(Intent.EXTRA_STREAM, uri);
                    startActivity(Intent.createChooser(intent, getString(R.string.share_title)));
                });

        menuItemClicks(R.id.save).compose(bindToLifecycle())
                .compose(ensurePermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE))
                .map(avoid -> getCurrentImage())
                .doOnNext(image -> MobclickAgent.onEvent(this, "save", image.getObjectId()))
                .observeOn(Schedulers.io()).flatMap(this::saveIfNeeded).observeOn(AndroidSchedulers.mainThread())
                .doOnNext(this::notifyMediaScanning).retry().subscribe(file -> {
                    ToastUtil.shorts(this, R.string.save_success, file.getPath());
                });

        final WallpaperManager wm = WallpaperManager.getInstance(this);

        menuItemClicks(R.id.set_wallpaper).compose(bindToLifecycle()).map(avoid -> getCurrentImage())
                .doOnNext(image -> MobclickAgent.onEvent(this, "set_wallpaper", image.getObjectId()))
                .observeOn(Schedulers.io()).flatMap(this::download).observeOn(AndroidSchedulers.mainThread())
                .map(file -> FileProvider.getUriForFile(this, AUTHORITY_IMAGES, file)).retry().subscribe(uri -> {
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
                        startActivity(wm.getCropAndSetWallpaperIntent(uri));
                    } else {
                        try {
                            wm.setStream(getContentResolver().openInputStream(uri));
                            ToastUtil.shorts(this, R.string.set_wallpaper_success);
                        } catch (IOException e) {
                            Log.e(TAG, "Failed to set wallpaper", e);
                            ToastUtil.shorts(this, e.getMessage(), e);
                        }
                    }
                });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        images.removeOnListChangedCallback(listener);
    }

    @Override
    protected void onResume() {
        super.onResume();
        MobclickAgent.onResume(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        MobclickAgent.onPause(this);
    }

    private Image getCurrentImage() {
        return images.get(binding.pager.getCurrentItem());
    }

    void fadeIn() {
        InOutAnimationUtils.animateIn(binding.toolbar, R.anim.viewer_toolbar_fade_in);
        ImmersiveUtil.exit(this);
    }

    void fadeOut() {
        InOutAnimationUtils.animateOut(binding.toolbar, R.anim.viewer_toolbar_fade_out);
        ImmersiveUtil.enter(this);
    }

    void toggleFade() {
        if (binding.toolbar.getVisibility() == View.VISIBLE) {
            fadeOut();
        } else {
            fadeIn();
        }
    }

    @Override
    public void onPullStart() {
        InOutAnimationUtils.animateOut(binding.toolbar, R.anim.viewer_toolbar_fade_out);
        ImmersiveUtil.exit(this);
    }

    @Override
    public void onPull(float progress) {
        progress = Math.min(1f, progress * 3f);
        background.setAlpha((int) (0xff * (1f - progress)));
    }

    @Override
    public void onPullCancel() {
        fadeIn();
    }

    @Override
    public void onPullComplete() {
        supportFinishAfterTransition();
    }

    public ViewerFragment getCurrent() {
        return (ViewerFragment) adapter.instantiateItem(binding.pager, binding.pager.getCurrentItem());
    }

    @Override
    public void supportFinishAfterTransition() {
        Intent data = new Intent();
        data.putExtra("index", binding.pager.getCurrentItem());
        setResult(RESULT_OK, data);

        ImmersiveUtil.exit(this);

        super.supportFinishAfterTransition();
    }

    private void notifyMediaScanning(File file) {
        MediaScannerConnection.scanFile(getApplicationContext(), new String[] { file.getPath() }, null, null);
    }

    private class Adapter extends FragmentStatePagerAdapter {

        public Adapter() {
            super(getSupportFragmentManager());
        }

        @Override
        public Fragment getItem(int position) {
            Image image = images.get(position);

            Bundle arguments = new Bundle();
            arguments.putParcelable("image", image);

            if (position == getIntent().getIntExtra("index", 0)) {
                arguments.putString("thumbnail", getIntent().getStringExtra("thumbnail"));
            }

            Fragment fragment = new ViewerFragment();
            fragment.setArguments(arguments);

            return fragment;
        }

        @Override
        public int getCount() {
            return images.size();
        }

    }

}