package com.kickstarter.ui.activities;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Pair;
import android.view.WindowManager;
import android.widget.TextView;
import com.jakewharton.rxbinding.view.RxView;
import com.jakewharton.rxbinding.widget.RxTextView;
import com.kickstarter.R;
import com.kickstarter.libs.ActivityRequestCodes;
import com.kickstarter.libs.BaseActivity;
import com.kickstarter.libs.RecyclerViewPaginator;
import com.kickstarter.libs.SwipeRefresher;
import com.kickstarter.libs.qualifiers.RequiresActivityViewModel;
import com.kickstarter.libs.rx.transformers.Transformers;
import com.kickstarter.libs.utils.ObjectUtils;
import com.kickstarter.libs.utils.ViewUtils;
import com.kickstarter.models.Project;
import com.kickstarter.ui.IntentKey;
import com.kickstarter.ui.adapters.CommentsAdapter;
import com.kickstarter.ui.data.LoginReason;
import com.kickstarter.ui.viewholders.EmptyCommentsViewHolder;
import com.kickstarter.ui.viewholders.ProjectContextViewHolder;
import com.kickstarter.viewmodels.CommentsViewModel;
import com.trello.rxlifecycle.ActivityEvent;
import butterknife.Bind;
import butterknife.BindString;
import butterknife.ButterKnife;
import butterknife.OnClick;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.subjects.PublishSubject;
import static com.kickstarter.libs.utils.TransitionUtils.slideInFromLeft;
@RequiresActivityViewModel(CommentsViewModel.class)
public final class CommentsActivity extends BaseActivity<CommentsViewModel> implements CommentsAdapter.Delegate {
private CommentsAdapter adapter;
private RecyclerViewPaginator recyclerViewPaginator;
private SwipeRefresher swipeRefresher;
private @NonNull PublishSubject<AlertDialog> alertDialog = PublishSubject.create();
protected @Bind(R.id.comment_button) TextView commentButtonTextView;
protected @Bind(R.id.comments_swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout;
protected @Bind(R.id.comments_recycler_view) RecyclerView recyclerView;
protected @BindString(R.string.social_error_could_not_post_try_again) String postCommentErrorString;
protected @BindString(R.string.project_comments_posted) String commentPostedString;
@Override
protected void onCreate(final @Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.comments_layout);
ButterKnife.bind(this);
adapter = new CommentsAdapter(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerViewPaginator = new RecyclerViewPaginator(recyclerView, viewModel.inputs::nextPage);
swipeRefresher = new SwipeRefresher(this, swipeRefreshLayout, viewModel.inputs::refresh, viewModel.outputs::isFetchingComments);
final Observable<TextView> commentBodyEditText = alertDialog
.map(a -> ButterKnife.findById(a, R.id.comment_body));
final Observable<TextView> postCommentButton = alertDialog
.map(a -> ButterKnife.findById(a, R.id.post_button));
final Observable<TextView> cancelButton = alertDialog
.map(a -> ButterKnife.findById(a, R.id.cancel_button));
cancelButton
.switchMap(RxView::clicks)
.observeOn(AndroidSchedulers.mainThread())
.compose(bindToLifecycle())
.subscribe(__ -> viewModel.inputs.commentDialogDismissed());
postCommentButton
.switchMap(RxView::clicks)
.compose(bindToLifecycle())
.subscribe(__ -> viewModel.inputs.postCommentClicked());
commentBodyEditText
.switchMap(t -> RxTextView.textChanges(t).skip(1))
.map(CharSequence::toString)
.compose(bindToLifecycle())
.subscribe(viewModel.inputs::commentBodyChanged);
viewModel.outputs.currentCommentBody()
.compose(Transformers.takePairWhen(commentBodyEditText))
.observeOn(AndroidSchedulers.mainThread())
.compose(bindToLifecycle())
.subscribe(ce -> ce.second.append(ce.first));
viewModel.outputs.commentsData()
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(adapter::takeData);
viewModel.outputs.enablePostButton()
.compose(Transformers.combineLatestPair(postCommentButton))
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bb -> setPostButtonEnabled(bb.second, bb.first));
viewModel.outputs.commentButtonHidden()
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(ViewUtils.setGone(this.commentButtonTextView));
viewModel.outputs.showCommentDialog()
.filter(projectAndShow -> projectAndShow != null)
.map(projectAndShow -> projectAndShow.first)
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::showCommentDialog);
alertDialog
.compose(Transformers.takeWhen(viewModel.outputs.dismissCommentDialog()))
.observeOn(AndroidSchedulers.mainThread())
.compose(bindToLifecycle())
.subscribe(this::dismissCommentDialog);
lifecycle()
.compose(Transformers.combineLatestPair(alertDialog))
.filter(ad -> ad.first == ActivityEvent.DESTROY)
.map(ad -> ad.second)
.observeOn(AndroidSchedulers.mainThread())
// NB: We dont want to bind to lifecycle because we want the destroy event.
// .compose(bindToLifecycle())
.take(1)
.subscribe(this::dismissCommentDialog);
toastMessages()
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(ViewUtils.showToast(this));
}
@Override
protected void onDestroy() {
super.onDestroy();
recyclerViewPaginator.stop();
recyclerView.setAdapter(null);
}
@Nullable
@OnClick(R.id.project_context_view)
public void projectContextViewClick() {
back();
}
public void commentsLogin() {
final Intent intent = new Intent(this, LoginToutActivity.class)
.putExtra(IntentKey.LOGIN_REASON, LoginReason.COMMENT_FEED);
startActivityForResult(intent, ActivityRequestCodes.LOGIN_FLOW);
}
@OnClick(R.id.comment_button)
protected void commentButtonClicked() {
viewModel.inputs.commentButtonClicked();
}
public void dismissCommentDialog(final @Nullable AlertDialog dialog) {
if (dialog != null) {
dialog.dismiss();
}
}
public void showCommentDialog(final @NonNull Project project) {
final AlertDialog commentDialog = new AlertDialog.Builder(this)
.setView(R.layout.comment_dialog)
.create();
commentDialog.show();
commentDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
/* Toolbar UI actions */
final TextView projectNameTextView = ButterKnife.findById(commentDialog, R.id.comment_project_name);
projectNameTextView.setText(project.name());
// Handle cancel-click region outside of dialog modal.
commentDialog.setOnCancelListener((final @NonNull DialogInterface dialogInterface) -> {
viewModel.inputs.commentDialogDismissed();
});
alertDialog.onNext(commentDialog);
}
public void setPostButtonEnabled(final @Nullable TextView postCommentButton, final boolean enabled) {
if (postCommentButton != null) {
postCommentButton.setEnabled(enabled);
}
}
@Override
public void projectContextClicked(final @NonNull ProjectContextViewHolder viewHolder) {
back();
}
@Override
public void emptyCommentsLoginClicked(final @NonNull EmptyCommentsViewHolder viewHolder) {
commentsLogin();
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final @Nullable Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode != ActivityRequestCodes.LOGIN_FLOW) {
return;
}
if (resultCode != RESULT_OK) {
return;
}
viewModel.inputs.loginSuccess();
}
@Override
protected @Nullable Pair<Integer, Integer> exitTransition() {
return slideInFromLeft();
}
private Observable<String> toastMessages() {
return viewModel.outputs.showPostCommentErrorToast()
.map(ObjectUtils.coalesceWith(postCommentErrorString))
.mergeWith(viewModel.outputs.showCommentPostedToast().map(__ -> commentPostedString));
}
}