ooo.oxo.moments.user.UserActivity.java Source code

Java tutorial

Introduction

Here is the source code for ooo.oxo.moments.user.UserActivity.java

Source

/*
 * Moments - To the best Instagram client
 * Copyright (C) 2015  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 2 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.moments.user;

import android.animation.Animator;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.transition.Transition;
import android.util.Log;
import android.util.Pair;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;

import java.util.List;

import butterknife.Bind;
import butterknife.BindColor;
import butterknife.BindDimen;
import butterknife.ButterKnife;
import jp.wasabeef.glide.transformations.CropCircleTransformation;
import ooo.oxo.moments.InstaApplication;
import ooo.oxo.moments.InstaSharedState;
import ooo.oxo.moments.R;
import ooo.oxo.moments.feed.FeedAdapter;
import ooo.oxo.moments.model.Media;
import ooo.oxo.moments.model.User;
import ooo.oxo.moments.net.Envelope;
import ooo.oxo.moments.net.UserApi;
import ooo.oxo.moments.util.StatusBarTintDelegate;
import ooo.oxo.moments.util.StatusBarUtils;
import ooo.oxo.moments.util.ViewGroupUtils;
import pocketknife.BindExtra;
import pocketknife.NotRequired;
import pocketknife.PocketKnife;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func2;

public class UserActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener,
        UserGridAdapter.GridListener, RequestListener<String, GlideDrawable> {

    private static final String TAG = "UserActivity";

    @Bind(R.id.appbar)
    AppBarLayout appbar;

    @Bind(R.id.collapsing_toolbar)
    CollapsingToolbarLayout collapsingToolbar;

    @Bind(R.id.toolbar)
    Toolbar toolbar;

    @Bind(R.id.refresher)
    SwipeRefreshLayout refresher;

    @Bind(R.id.content)
    RecyclerView content;

    @Bind(R.id.avatar)
    ImageView avatar;

    @Bind(R.id.full_name)
    TextView fullName;

    @Bind(R.id.user_name)
    TextView userName;

    @Bind(R.id.bio)
    TextView bio;

    @Bind(R.id.counts)
    View counts;

    @Bind(R.id.posts)
    TextView posts;

    @Bind(R.id.followers)
    TextView followers;

    @Bind(R.id.following)
    TextView following;

    @BindColor(R.color.primary)
    int colorPrimary;

    @BindDimen(R.dimen.srl_start)
    int refresherStart;

    @BindDimen(R.dimen.srl_length)
    int refresherLength;

    @BindDimen(R.dimen.item_margin_grid)
    int marginGrid;

    @BindDimen(R.dimen.item_margin_stream)
    int marginStream;

    int statusBarHeight = 0;

    @BindExtra("id")
    @NotRequired
    String id;

    @BindExtra("user")
    @NotRequired
    User user;

    @BindExtra("from_post")
    @NotRequired
    String fromPostId;

    private MenuItem viewAsGrid;
    private MenuItem viewAsStream;

    private String accessToken;

    private UserApi userApi;

    private FeedAdapter streamAdapter;
    private UserGridAdapter gridAdapter;

    private Animator avatarReveal;

    private boolean isEntered = true;

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

        setContentView(R.layout.user_activity);

        ButterKnife.bind(this);
        PocketKnife.bindExtras(this);

        setTitle(null);
        setSupportActionBar(toolbar);

        statusBarHeight = StatusBarUtils.getStatusBarHeight(this);

        collapsingToolbar.setPadding(0, statusBarHeight, 0, 0);

        appbar.addOnOffsetChangedListener((AppBarLayout appbar, int i) -> refresher.setEnabled(i == 0));

        toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
        toolbar.setNavigationOnClickListener(v -> supportFinishAfterTransition());
        toolbar.post(() -> appbar
                .addOnOffsetChangedListener(new StatusBarTintDelegate(this, toolbar.getHeight(), statusBarHeight)));

        refresher.setProgressViewOffset(true, refresherStart, refresherStart + refresherLength);
        refresher.setColorSchemeColors(colorPrimary);
        refresher.setOnRefreshListener(this);

        accessToken = InstaSharedState.getInstance().getAccessToken();

        userApi = InstaApplication.from(this).createApi(UserApi.class);

        if (user != null) {
            populateProfile(user);
        }

        if (id == null && user != null) {
            id = user.id;
        }

        if (id == null) {
            throw new IllegalStateException("Must specify which user to load");
        }

        if (Build.VERSION.SDK_INT >= 21 && fromPostId != null) {
            isEntered = false;
            supportPostponeEnterTransition();
            ViewCompat.setTransitionName(avatar, id + "_" + fromPostId + "_avatar");

            getWindow().getSharedElementEnterTransition().addListener(new Transition.TransitionListener() {
                @Override
                public void onTransitionStart(Transition transition) {
                }

                @Override
                public void onTransitionEnd(Transition transition) {
                    //revealAvatarView();
                }

                @Override
                public void onTransitionCancel(Transition transition) {
                }

                @Override
                public void onTransitionPause(Transition transition) {
                }

                @Override
                public void onTransitionResume(Transition transition) {
                }
            });
        }

        streamAdapter = new FeedAdapter(this, this);
        gridAdapter = new UserGridAdapter(this, this);

        viewAsStream();

        load();
    }

    @Override
    public void onRefresh() {
        load();
    }

    private void load() {
        refresher.post(() -> refresher.setRefreshing(true));

        Observable.combineLatest(userApi.profile(id, accessToken), userApi.timeline(id, 200, accessToken),
                (Func2<Envelope<User>, Envelope<List<Media>>, Pair<Envelope<User>, Envelope<List<Media>>>>) Pair::new)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(result -> populate(result.first, result.second),
                        throwable -> Log.d(TAG, "failed to load user", throwable));
    }

    @TargetApi(21)
    private void setupAvatarReveal() { // FIXME: it flashes, unexpectedly
        int[] bounds = ViewGroupUtils.calculateBounds(avatar, appbar);
        avatarReveal = ViewAnimationUtils.createCircularReveal(appbar,
                (int) (bounds[0] + (float) avatar.getWidth() / 2f),
                (int) (bounds[1] + (float) avatar.getHeight() / 2f), (float) avatar.getWidth() / 2f,
                (float) bounds[2]);
    }

    @TargetApi(21)
    private void revealAvatarView() {
        if (avatarReveal != null) {
            avatarReveal.start();
            avatarReveal = null;
        }
    }

    private void populate(Envelope<User> profile, Envelope<List<Media>> timeline) {
        refresher.setRefreshing(false);

        if (profile == null || timeline == null) {
            return;
        }

        streamAdapter.setFeed(timeline.data);
        gridAdapter.setFeed(timeline.data);

        populateProfile(profile.data);
    }

    private void populateProfile(User profile) {
        Glide.with(this).load(profile.profilePicture).diskCacheStrategy(DiskCacheStrategy.ALL)
                .bitmapTransform(new CropCircleTransformation(this)).listener(this).into(avatar);

        userName.setText(profile.username);

        if (TextUtils.isEmpty(profile.fullName)) {
            fullName.setVisibility(View.GONE);
        } else {
            fullName.setText(profile.fullName);
            fullName.setVisibility(View.VISIBLE);
        }

        if (TextUtils.isEmpty(profile.bio)) {
            bio.setVisibility(View.GONE);
        } else {
            bio.setText(profile.bio);
            bio.setVisibility(View.VISIBLE);
        }

        if (profile.counts != null) {
            posts.setText(String.valueOf(profile.counts.media));
            followers.setText(String.valueOf(profile.counts.followedBy));
            following.setText(String.valueOf(profile.counts.follows));
            counts.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
        supportStartPostponedEnterTransition();
        isEntered = true;
        return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target,
            boolean isFromMemoryCache, boolean isFirstResource) {
        if (!isEntered) {
            //setupAvatarReveal();
            supportStartPostponedEnterTransition();
            isEntered = true;
        }

        return false;
    }

    @Override
    public void onUserClick(FeedAdapter.ViewHolder holder) {
    }

    @Override
    public void onUserClick(String id) {
        if (this.id.equals(id)) {
            return;
        }

        Intent intent = new Intent(this, UserActivity.class);
        intent.putExtra("id", id);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

    @Override
    public void onImageClick(FeedAdapter.ViewHolder holder) {
    }

    @Override
    public void onImageClick(UserGridAdapter.ViewHolder holder) {
    }

    @Override
    public void onLikesClick(FeedAdapter.ViewHolder holder) {
    }

    @Override
    public void onLike(FeedAdapter.ViewHolder holder) {
    }

    @Override
    public void onComment(FeedAdapter.ViewHolder holder) {
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.user, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        viewAsGrid = menu.findItem(R.id.view_as_grid);
        viewAsStream = menu.findItem(R.id.view_as_stream);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.view_as_grid:
            viewAsGrid.setVisible(false);
            viewAsStream.setVisible(true);
            viewAsGrid();
            return true;
        case R.id.view_as_stream:
            viewAsStream.setVisible(false);
            viewAsGrid.setVisible(true);
            viewAsStream();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void viewAsStream() {
        content.setPadding(marginStream, marginStream, marginStream, marginStream);
        content.setLayoutManager(new LinearLayoutManager(this));
        content.setAdapter(streamAdapter);
    }

    private void viewAsGrid() {
        content.setPadding(marginGrid, marginGrid, marginGrid, marginGrid);
        content.setLayoutManager(new GridLayoutManager(this, 3));
        content.setAdapter(gridAdapter);
    }

}