package com.badoo.chateau.ui.chat.messages;
import android.support.annotation.NonNull;
import android.util.Log;
import com.badoo.barf.mvp.BaseRxPresenter;
import com.badoo.barf.rx.ScheduleOn;
import com.badoo.chateau.core.model.Message;
import com.badoo.chateau.core.repos.messages.MessageDataSource.Update;
import com.badoo.chateau.core.usecases.conversations.MarkConversationRead;
import com.badoo.chateau.core.usecases.messages.LoadMessages;
import com.badoo.chateau.core.usecases.messages.SendMessage;
import com.badoo.chateau.core.usecases.messages.SubscribeToMessageUpdates;
import java.util.Collections;
import java.util.List;
import rx.android.schedulers.AndroidSchedulers;
import static com.badoo.chateau.core.repos.messages.MessageDataSource.Update.Action;
public class BaseMessageListPresenter<M extends Message>
extends BaseRxPresenter implements MessageListPresenter<M> {
private static final String TAG = BaseMessageListPresenter.class.getSimpleName();
@NonNull
private final String mConversationId;
@NonNull
private final MessageListView<M> mView;
private boolean mCanLoadOlder = true;
// Use cases
@NonNull
private LoadMessages<M> mLoadMessages;
@NonNull
private final SubscribeToMessageUpdates<M> mSubscribeToMessageUpdates;
@NonNull
private final MarkConversationRead mMarkConversationRead;
@NonNull
private final SendMessage<M> mSendMessage;
public BaseMessageListPresenter(@NonNull String conversationId,
@NonNull MessageListView<M> view,
@NonNull LoadMessages<M> loadMessages,
@NonNull SubscribeToMessageUpdates<M> subscribeToMessageUpdates,
@NonNull MarkConversationRead markConversationRead,
@NonNull SendMessage<M> sendMessage) {
mConversationId = conversationId;
mView = view;
mLoadMessages = loadMessages;
mSubscribeToMessageUpdates = subscribeToMessageUpdates;
mMarkConversationRead = markConversationRead;
mSendMessage = sendMessage;
}
@Override
public void onStart() {
super.onStart();
// Setup subscriptions
manage(mSubscribeToMessageUpdates.forConversation(mConversationId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onUpdate, this::onNonFatalError));
// Request data
reload();
}
private void onUpdate(Update<M> update) {
if (update.getAction() == Action.ADDED) {
onNewerLoaded(Collections.singletonList(update.getNewMessage()));
}
else if (update.getAction() == Action.UPDATED) {
onReplace(update.getOldMessage(), update.getNewMessage());
}
else if (update.getAction() == Action.INVALIDATE_ALL) {
reload();
}
}
@Override
public void onMoreMessagesRequired() {
if (mCanLoadOlder) {
loadOlder();
}
}
@Override
public void onResendClicked(@NonNull M message) {
manage(mSendMessage.execute(mConversationId, message).subscribe());
}
protected void reload() {
// We need to put this in some point if the view is empty. But if it's shown even for a second and then hidden when coming
// back it fucks up the transition animation
//mView.showLoadingMoreMessages(true);
manage(mLoadMessages.all(mConversationId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
mView.showLoadingMoreMessages(false);
mCanLoadOlder = result.canLoadOlder();
onReloaded(result.getMessages());
if (result.canLoadNewer()) {
loadNewer();
}
}, this::onFatalError));
}
protected void onReloaded(List<M> messages) {
markConversationRead();
mView.showMessages(messages);
}
protected void loadNewer() {
manage(mLoadMessages.newer(mConversationId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
onNewerLoaded(result.getMessages());
if (result.canLoadNewer()) {
loadNewer();
}
}, this::onFatalError));
}
protected void onNewerLoaded(List<M> messages) {
markConversationRead();
mView.showNewerMessages(messages);
}
protected void loadOlder() {
mCanLoadOlder = false;
mView.showLoadingMoreMessages(true);
manage(mLoadMessages.older(mConversationId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
mCanLoadOlder = result.canLoadOlder();
mView.showLoadingMoreMessages(false);
onOlderLoaded(result.getMessages());
}, this::onFatalError));
}
protected void onOlderLoaded(List<M> messages) {
mView.showOlderMessages(messages);
}
protected void onReplace(@NonNull M oldMessage, @NonNull M newMessage) {
mView.replaceMessage(oldMessage, newMessage);
}
private void markConversationRead() {
manage(mMarkConversationRead.execute(mConversationId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(conversation -> {
}, this::onNonFatalError));
}
private void onFatalError(Throwable throwable) {
Log.e(TAG, "Fatal error", throwable);
mView.showError(true, throwable);
}
private void onNonFatalError(Throwable throwable) {
Log.w(TAG, "Non-fatal error", throwable);
mView.showError(false, throwable);
}
}