package com.malmstein.yahnac.comments;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import com.malmstein.yahnac.HNewsActivity;
import com.malmstein.yahnac.R;
import com.malmstein.yahnac.data.HNewsContract;
import com.malmstein.yahnac.data.updater.LoginSharedPreferences;
import com.malmstein.yahnac.model.Story;
import com.malmstein.yahnac.views.SnackBarView;
import com.malmstein.yahnac.views.StoryHeaderView;
import com.novoda.notils.caster.Views;
import com.novoda.notils.exception.DeveloperError;
public class CommentsPresenter implements ReplyView.Listener, CommentsAdapter.Listener, LoaderManager.LoaderCallbacks<Cursor> {
public static final String VIEW_NAME_HEADER_TITLE = "detail:header:title";
private static final int COMMENTS_LOADER = 1006;
private final HNewsActivity activity;
private final SwipeRefreshLayout.OnRefreshListener refreshListener;
private int croutonAnimationDuration;
private int croutonBackgroundAlpha;
private LoginSharedPreferences loginSharedPreferences;
private StoryHeaderView storyHeaderView;
private SnackBarView snackbarView;
private ReplyView replyView;
private FloatingActionButton replyFab;
private CommentsView commentsView;
private Animator mCircularReveal;
public CommentsPresenter(HNewsActivity activity, SwipeRefreshLayout.OnRefreshListener refreshListener) {
this.activity = activity;
this.refreshListener = refreshListener;
}
private Story getStory() {
if (activity.getIntent().getExtras().containsKey(CommentsActivity.ARG_STORY)) {
return (Story) activity.getIntent().getExtras().getSerializable(CommentsActivity.ARG_STORY);
} else {
throw new DeveloperError("Missing argument");
}
}
public void onCreate() {
storyHeaderView = Views.findById(activity, R.id.story_header_view);
replyFab = Views.findById(activity, R.id.story_reply_action);
replyView = Views.findById(activity, R.id.reply_view);
snackbarView = Views.findById(activity, R.id.snackbar);
commentsView = Views.findById(activity, R.id.comments_view);
ViewCompat.setTransitionName(storyHeaderView, VIEW_NAME_HEADER_TITLE);
activity.setupSubActivity();
setupHeaderView();
setupSnackbar();
setupCommentsView();
setupReplyListener();
loadComments();
}
public void onPostCreate(boolean online) {
onRefresh(online);
}
public void onCreateOptionsMenu(Menu menu) {
activity.getMenuInflater().inflate(R.menu.menu_comments, menu);
if (getStory().isHackerNewsLocalItem()) {
MenuItem comments = menu.findItem(R.id.action_article);
comments.setVisible(false);
}
MenuItem bookmarks = menu.findItem(R.id.action_bookmark);
if (getStory().isBookmark()) {
checkBookmarkMenuItem(bookmarks);
} else {
uncheckBookmarkMenuItem(bookmarks);
}
}
public void onBookmarkUnselected(MenuItem item) {
uncheckBookmarkMenuItem(item);
}
public void onBookmarkSelected(MenuItem item) {
item.setChecked(true);
item.setIcon(R.drawable.ic_bookmark_white);
}
private void setupHeaderView() {
storyHeaderView.updateWith(getStory());
}
private void setupSnackbar() {
croutonBackgroundAlpha = activity.getResources().getInteger(R.integer.feed_crouton_background_alpha);
croutonAnimationDuration = activity.getResources().getInteger(R.integer.feed_crouton_animation_duration);
}
private void setupCommentsView() {
commentsView.setupWith(this, refreshListener, getStory());
}
private void setupReplyListener() {
replyView.setListener(this);
loginSharedPreferences = LoginSharedPreferences.newInstance();
if (loginSharedPreferences.isLoggedIn()) {
replyFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showReplyViewForStory();
}
});
} else {
replyFab.setActivated(false);
replyFab.setVisibility(View.GONE);
}
}
private void loadComments() {
activity.getLoaderManager().initLoader(COMMENTS_LOADER, null, this);
}
private void showReplyViewForStory() {
replyView.setStoryId(getStory().getId());
showReplyView();
}
public void showReplyViewForComment(Long commentId) {
replyView.setCommentId(commentId);
replyView.setStoryId(getStory().getId());
showReplyView();
}
private void showReplyView() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
int centerX = (replyFab.getLeft() + replyFab.getRight()) / 2;
int centerY = (replyFab.getTop() + replyFab.getBottom()) / 2;
int finalRadius = Math.max(replyView.getWidth(), replyView.getHeight());
mCircularReveal = ViewAnimationUtils.createCircularReveal(
replyView, centerX, centerY, 0, finalRadius);
mCircularReveal.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mCircularReveal.removeListener(this);
}
});
mCircularReveal.start();
}
replyFab.hide();
replyView.setVisibility(View.VISIBLE);
commentsView.setVisibility(View.GONE);
}
private void hideReplyView() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
int cx = (replyFab.getLeft() + replyFab.getRight()) / 2;
int cy = (replyFab.getTop() + replyFab.getBottom()) / 2;
int initialRadius = replyView.getWidth();
Animator anim =
ViewAnimationUtils.createCircularReveal(replyView, cx, cy, initialRadius, 0);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
replyView.clearAndHide();
}
});
anim.start();
} else {
replyView.clearAndHide();
}
replyFab.show();
commentsView.setVisibility(View.VISIBLE);
}
private void checkBookmarkMenuItem(MenuItem bookmarks) {
bookmarks.setChecked(true);
bookmarks.setIcon(R.drawable.ic_bookmark_white);
}
private void uncheckBookmarkMenuItem(MenuItem bookmarks) {
bookmarks.setChecked(false);
bookmarks.setIcon(R.drawable.ic_bookmark_outline_white);
}
private void showAddedBookmarkSnackbar(final CommentsOperator commentsOperator, final Story story) {
snackbarView.showSnackBar(activity.getResources().getText(R.string.feed_snackbar_added_bookmark))
.withBackgroundColor(R.color.black, croutonBackgroundAlpha)
.withAnimationDuration(croutonAnimationDuration)
.withUndoClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
snackbarView.hideCrouton();
commentsOperator.onBookmarkUnselected();
showRemovedBookmarkSnackbar(commentsOperator, story);
}
})
.animating();
}
private void showRemovedBookmarkSnackbar(final CommentsOperator commentsOperator, final Story story) {
snackbarView.showSnackBar(activity.getResources().getText(R.string.feed_snackbar_removed_bookmark))
.withBackgroundColor(R.color.black, croutonBackgroundAlpha)
.withAnimationDuration(croutonAnimationDuration)
.withUndoClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
snackbarView.hideCrouton();
commentsOperator.onBookmarkSelected();
showAddedBookmarkSnackbar(commentsOperator, story);
}
})
.animating();
}
public void showNotImplemented() {
snackbarView.showSnackBar(activity.getResources().getText(R.string.feed_snackbar_not_implemented))
.withBackgroundColor(R.color.black, croutonBackgroundAlpha)
.withAnimationDuration(croutonAnimationDuration)
.animating();
}
public void showLoginExpired() {
snackbarView.showSnackBar(activity.getResources().getText(R.string.login_expired_message))
.withBackgroundColor(R.color.black, croutonBackgroundAlpha)
.withAnimationDuration(croutonAnimationDuration)
.withCustomTextClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
activity.navigate().toLogin(null);
}
}, R.string.feed_snackbar_text_sign_in)
.animating();
}
public void showContentUpdating() {
commentsView.startRefreshing();
}
@Override
public void onReplyCancelled() {
hideReplyView();
}
@Override
public void onReplySuccessful() {
hideReplyView();
refreshListener.onRefresh();
}
@Override
public void onLoginExpired() {
hideReplyView();
showLoginExpired();
}
@Override
public void onCommentReplyAction(Long id) {
showReplyViewForComment(id);
}
@Override
public void onCommentVoteAction(Long id) {
showNotImplemented();
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri commentsUri = HNewsContract.CommentsEntry.buildCommentsUri();
return new CursorLoader(
activity,
commentsUri,
HNewsContract.CommentsEntry.COMMENT_COLUMNS,
HNewsContract.StoryEntry.ITEM_ID + " = ?",
new String[]{String.valueOf(getStory().getId())},
null
);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
commentsView.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
commentsView.swapCursor(null);
}
public void hideRefreshAnimation() {
commentsView.stopRefreshing();
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_bookmark:
if (item.isChecked()) {
onBookmarkUnselected(item);
} else {
onBookmarkSelected(item);
}
return true;
case android.R.id.home:
activity.finish();
return true;
default:
return false;
}
}
public void onRefresh(boolean isOnline) {
if (isOnline) {
showContentUpdating();
} else {
hideRefreshAnimation();
}
}
public void onBackPressed() {
if (inReplyMode()) {
hideReplyView();
} else {
activity.supportFinishAfterTransition();
}
}
public boolean inReplyMode() {
return replyView.getVisibility() == View.VISIBLE;
}
}