package im.actor.sdk.controllers.conversation;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import im.actor.core.entity.GroupType;
import im.actor.core.entity.Peer;
import im.actor.core.entity.PeerType;
import im.actor.core.entity.Sticker;
import im.actor.core.network.RpcException;
import im.actor.core.viewmodel.ConversationVM;
import im.actor.core.viewmodel.GroupVM;
import im.actor.core.viewmodel.UserVM;
import im.actor.runtime.mvvm.Value;
import im.actor.runtime.mvvm.ValueChangedListener;
import im.actor.runtime.mvvm.ValueDoubleChangedListener;
import im.actor.runtime.mvvm.ValueListener;
import im.actor.sdk.ActorSDK;
import im.actor.sdk.ActorSDKLauncher;
import im.actor.sdk.R;
import im.actor.sdk.controllers.BaseFragment;
import im.actor.sdk.controllers.conversation.attach.AbsAttachFragment;
import im.actor.sdk.controllers.conversation.inputbar.InputBarCallback;
import im.actor.sdk.controllers.conversation.inputbar.InputBarFragment;
import im.actor.sdk.controllers.conversation.mentions.AutocompleteCallback;
import im.actor.sdk.controllers.conversation.mentions.AutocompleteFragment;
import im.actor.sdk.controllers.conversation.messages.MessagesDefaultFragment;
import im.actor.sdk.controllers.conversation.messages.MessagesFragmentCallback;
import im.actor.sdk.controllers.conversation.placeholder.EmptyChatPlaceholder;
import im.actor.sdk.controllers.conversation.quote.QuoteCallback;
import im.actor.sdk.controllers.conversation.quote.QuoteFragment;
import im.actor.sdk.controllers.conversation.attach.AttachFragment;
import im.actor.sdk.controllers.conversation.toolbar.ChatToolbarFragment;
import static im.actor.sdk.util.ActorSDKMessenger.groups;
import static im.actor.sdk.util.ActorSDKMessenger.messenger;
import static im.actor.sdk.util.ActorSDKMessenger.users;
public class ChatFragment extends BaseFragment implements InputBarCallback, MessagesFragmentCallback, QuoteCallback,
AutocompleteCallback {
public static ChatFragment create(Peer peer) {
ChatFragment res = new ChatFragment();
Bundle bundle = new Bundle();
bundle.putLong("peer", peer.getUnuqueId());
res.setArguments(bundle);
return res;
}
private View quoteContainer;
private View inputContainer;
private View inputOverlayContainer;
private View emptyContainer;
private TextView inputOverlayText;
private Peer peer;
private long editRid;
private String currentQuote;
public ChatFragment() {
setUnbindOnPause(true);
}
@Override
public void onCreate(Bundle saveInstance) {
super.onCreate(saveInstance);
peer = Peer.fromUniqueId(getArguments().getLong("peer"));
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View res = inflater.inflate(R.layout.fragment_chat, container, false);
quoteContainer = res.findViewById(R.id.quoteFragment);
res.findViewById(R.id.sendContainer).setBackgroundColor(style.getMainBackgroundColor());
inputContainer = res.findViewById(R.id.sendFragment);
inputOverlayContainer = res.findViewById(R.id.inputOverlay);
inputOverlayContainer.setBackgroundColor(style.getMainBackgroundColor());
inputOverlayText = (TextView) res.findViewById(R.id.overlayText);
inputOverlayText.setOnClickListener(view -> onOverlayPressed());
inputOverlayContainer.setVisibility(View.GONE);
emptyContainer = res.findViewById(R.id.emptyPlaceholder);
emptyContainer.setVisibility(View.GONE);
if (savedInstanceState == null) {
Fragment toolbarFragment = ActorSDK.sharedActor().getDelegate().fragmentForToolbar(peer);
if (toolbarFragment == null) {
toolbarFragment = new ChatToolbarFragment(peer);
}
InputBarFragment inputBarFragment = ActorSDK.sharedActor().getDelegate().fragmentForChatInput();
if (inputBarFragment == null) {
inputBarFragment = new InputBarFragment();
}
AutocompleteFragment autocompleteFragment = ActorSDK.sharedActor().getDelegate().fragmentForAutocomplete(peer);
if (autocompleteFragment == null) {
autocompleteFragment = AutocompleteFragment.create(peer);
autocompleteFragment.setUnderlyingView(res.findViewById(R.id.messagesFragment));
}
QuoteFragment quoteFragment = ActorSDK.sharedActor().getDelegate().fragmentForQuote();
if (quoteFragment == null) {
quoteFragment = new QuoteFragment();
}
MessagesDefaultFragment messagesDefaultFragment = MessagesDefaultFragment.create(peer);
messagesDefaultFragment.setNewMessageListener(inputBarFragment);
getChildFragmentManager().beginTransaction()
.add(toolbarFragment, "toolbar")
.add(R.id.messagesFragment, messagesDefaultFragment)
.add(R.id.sendFragment, inputBarFragment)
.add(R.id.quoteFragment, quoteFragment)
.add(R.id.emptyPlaceholder, new EmptyChatPlaceholder())
.add(R.id.autocompleteContainer, autocompleteFragment)
.commitNow();
AbsAttachFragment fragment = ActorSDK.sharedActor().getDelegate().fragmentForAttachMenu(peer);
if (fragment == null) {
fragment = new AttachFragment(peer);
}
getFragmentManager().beginTransaction()
.add(R.id.overlay, fragment)
.commit();
}
return res;
}
@Override
public void onResume() {
super.onResume();
findInputBar().setText(messenger().loadDraft(peer), true);
if (peer.getPeerType() == PeerType.PRIVATE) {
UserVM userVM = users().get(peer.getPeerId());
if (userVM.isBot()) {
ConversationVM conversationVM = messenger().getConversationVM(peer);
bind(conversationVM.getIsEmpty(), conversationVM.getIsLoaded(), (isEmpty, valueModel, isLoaded, valueModel2) -> {
if (isEmpty) {
inputOverlayText.setText(R.string.chat_empty_bot);
inputOverlayText.setTextColor(style.getListActionColor());
inputOverlayText.setClickable(true);
showView(inputOverlayContainer, false);
goneView(inputContainer, false);
} else {
goneView(inputOverlayContainer, false);
showView(inputContainer, false);
}
if (isEmpty && isLoaded) {
showView(emptyContainer, false);
} else {
hideView(emptyContainer, false);
}
});
bind(userVM.getAbout(), (val, valueModel) -> {
if (val == null) {
findEmptyPlaceholder().setText(getString(R.string.chat_empty_bot_about));
} else {
findEmptyPlaceholder().setText(val);
}
});
} else {
bind(userVM.getIsBlocked(), (val, valueModel) -> {
if (val) {
inputOverlayText.setText(R.string.blocked_unblock);
inputOverlayText.setTextColor(style.getListActionColor());
inputOverlayText.setClickable(true);
showView(inputOverlayContainer, false);
goneView(inputContainer, false);
} else {
goneView(inputOverlayContainer, false);
showView(inputContainer, false);
}
});
}
} else if (peer.getPeerType() == PeerType.GROUP) {
GroupVM groupVM = groups().get(peer.getPeerId());
bind(groupVM.isMember(), groupVM.getIsCanWriteMessage(), (isMember, valueModel, canWriteMessage, valueModel2) -> {
if (canWriteMessage) {
goneView(inputOverlayContainer, false);
showView(inputContainer, false);
} else if (isMember) {
if (messenger().isNotificationsEnabled(peer)) {
inputOverlayText.setText(getString(R.string.chat_mute));
} else {
inputOverlayText.setText(getString(R.string.chat_unmute));
}
inputOverlayText.setTextColor(style.getListActionColor());
inputOverlayText.setClickable(true);
inputOverlayText.setEnabled(true);
showView(inputOverlayContainer, false);
goneView(inputContainer, false);
} else if (groupVM.getIsCanJoin().get()) {
inputOverlayText.setText(getString(R.string.join));
inputOverlayText.setTextColor(style.getListActionColor());
inputOverlayText.setClickable(true);
inputOverlayText.setEnabled(true);
showView(inputOverlayContainer, false);
goneView(inputContainer, false);
} else if (groupVM.getIsDeleted().get()) {
inputOverlayText.setText(groupVM.getGroupType() == GroupType.CHANNEL ? R.string.channel_deleted : R.string.group_deleted);
inputOverlayText.setTextColor(style.getListActionColor());
inputOverlayText.setClickable(false);
inputOverlayText.setEnabled(false);
showView(inputOverlayContainer, false);
goneView(inputContainer, false);
} else {
inputOverlayText.setText(R.string.chat_not_member);
inputOverlayText.setTextColor(style.getListActionColor());
inputOverlayText.setClickable(false);
inputOverlayText.setEnabled(false);
showView(inputOverlayContainer, false);
goneView(inputContainer, false);
}
});
}
}
public void onOverlayPressed() {
if (peer.getPeerType() == PeerType.PRIVATE) {
UserVM userVM = users().get(peer.getPeerId());
if (userVM.isBot()) {
messenger().sendMessage(peer, "/start");
} else {
if (userVM.getIsBlocked().get()) {
execute(messenger().unblockUser(userVM.getId()));
}
}
} else if (peer.getPeerType() == PeerType.GROUP) {
GroupVM groupVM = groups().get(peer.getPeerId());
if (groupVM.isMember().get()) {
if (messenger().isNotificationsEnabled(peer)) {
messenger().changeNotificationsEnabled(peer, false);
inputOverlayText.setText(getString(R.string.chat_unmute));
} else {
messenger().changeNotificationsEnabled(peer, true);
inputOverlayText.setText(getString(R.string.chat_mute));
}
} else if (groupVM.getIsCanJoin().get()) {
messenger().joinGroup(groupVM.getId());
} else {
// TODO: Rejoin
}
}
}
public boolean onBackPressed() {
// Share Menu
AbsAttachFragment attachFragment = findShareFragment();
if (attachFragment != null) {
if (attachFragment.onBackPressed()) {
return true;
}
}
if (findInputBar().onBackPressed()) {
return true;
}
// Message Edit
if (editRid != 0) {
editRid = 0;
findInputBar().setText("");
hideQuote();
return true;
}
// Message Quoting
if (currentQuote != null) {
currentQuote = null;
hideQuote();
return true;
}
return false;
}
@Override
public void onTextFocusChanged(boolean isFocused) {
}
@Override
public void onTyping() {
messenger().onTyping(peer);
}
@Override
public void onTextChanged(String text) {
}
@Override
public void onAutoCompleteWordChanged(String text) {
findAutocomplete().onCurrentWordChanged(text);
}
@Override
public void onTextSent(String sequence) {
if (sequence.trim().length() > 0) {
if (editRid == 0) {
if (currentQuote != null) {
messenger().sendMessage(peer, currentQuote + sequence);
currentQuote = null;
hideQuote();
} else {
messenger().sendMessage(peer, sequence);
}
} else {
messenger().updateMessage(peer, sequence, editRid).failure(e -> {
Activity activity = getActivity();
if (activity != null) {
RpcException re = (RpcException) e;
String error;
if (re.getTag().equals("NOT_IN_TIME_WINDOW")) {
error = getString(R.string.edit_message_error_slowpoke);
} else if (re.getTag().equals("NOT_LAST_MESSAGE")) {
error = getString(R.string.edit_message_error_not_last);
} else {
error = re.getMessage();
}
Toast.makeText(activity, error, Toast.LENGTH_LONG).show();
}
});
editRid = 0;
hideQuote();
}
findInputBar().setText("");
}
}
@Override
public void onAudioSent(int duration, String descriptor) {
messenger().sendVoice(peer, duration, descriptor);
}
@Override
public void onStickerSent(Sticker sticker) {
messenger().sendSticker(peer, sticker);
}
@Override
public void onAttachPressed() {
findInputBar().clearFocus();
AbsAttachFragment attachFragment = findShareFragment();
if (attachFragment != null) {
quoteContainer.postDelayed(() -> attachFragment.show(), 200);
}
}
@Override
public void onAvatarClick(int uid) {
ActorSDKLauncher.startProfileActivity(getActivity(), uid);
}
@Override
public void onAvatarLongClick(int uid) {
insertMention(uid);
}
@Override
public void onMentionPicked(String name) {
findInputBar().replaceCurrentWord(name);
}
@Override
public void onCommandPicked(String command) {
messenger().sendMessage(peer, "/" + command);
findInputBar().setText("");
findAutocomplete().onCurrentWordChanged("");
}
public void insertMention(int uid) {
UserVM user = users().get(uid);
String name = user.getName().get();
String nick = user.getNick().get();
String text = findInputBar().getText();
if (text.length() > 0 && !text.endsWith(" ")) {
text = text + " ";
}
String mentionString;
if (nick != null) {
mentionString = "@" + nick;
} else {
mentionString = name;
}
if (text.length() == 0) {
mentionString += ": ";
} else {
mentionString += " ";
}
findInputBar().setText(text + mentionString);
findInputBar().requestFocus();
}
@Override
public void onMessageEdit(long rid, String text) {
editRid = rid;
findInputBar().setText(text);
showQuote(text, false);
}
@Override
public void onMessageQuote(String text) {
showQuote(text, true);
currentQuote = text;
}
@Override
public void onQuoteCancelled() {
if (editRid != 0) {
editRid = 0;
findInputBar().setText("");
}
currentQuote = null;
hideQuote();
}
@Override
public void onPause() {
super.onPause();
messenger().saveDraft(peer, findInputBar().getText());
}
@Override
public void onDestroyView() {
super.onDestroyView();
quoteContainer = null;
}
//
// Tools
//
private InputBarFragment findInputBar() {
return ((InputBarFragment) getChildFragmentManager().findFragmentById(R.id.sendFragment));
}
private QuoteFragment findQuoteFragment() {
return ((QuoteFragment) getChildFragmentManager().findFragmentById(R.id.quoteFragment));
}
private AbsAttachFragment findShareFragment() {
return ((AbsAttachFragment) getFragmentManager().findFragmentById(R.id.overlay));
}
private EmptyChatPlaceholder findEmptyPlaceholder() {
return ((EmptyChatPlaceholder) getChildFragmentManager().findFragmentById(R.id.emptyPlaceholder));
}
private AutocompleteFragment findAutocomplete() {
return ((AutocompleteFragment) getChildFragmentManager().findFragmentById(R.id.autocompleteContainer));
}
private void hideQuote() {
hideView(quoteContainer);
findInputBar().setDisableOnEmptyText(true);
findInputBar().setAudioEnabled(true);
findInputBar().setAttachEnabled(true);
}
private void showQuote(String text, boolean isQuote) {
showView(quoteContainer);
findQuoteFragment().setText(text, isQuote);
findInputBar().setDisableOnEmptyText(false);
findInputBar().setAudioEnabled(false);
findInputBar().setAttachEnabled(false);
}
}