package com.socialize.ui.comment;
import android.app.ProgressDialog;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.socialize.ConfigUtils;
import com.socialize.android.ioc.IBeanFactory;
import com.socialize.api.SocializeSession;
import com.socialize.api.action.comment.CommentOptions;
import com.socialize.api.action.comment.CommentUtilsProxy;
import com.socialize.api.action.comment.SubscriptionUtilsProxy;
import com.socialize.api.action.user.UserUtilsProxy;
import com.socialize.config.SocializeConfig;
import com.socialize.entity.*;
import com.socialize.error.SocializeException;
import com.socialize.i18n.I18NConstants;
import com.socialize.listener.comment.CommentAddListener;
import com.socialize.listener.comment.CommentListListener;
import com.socialize.listener.subscription.SubscriptionCheckListener;
import com.socialize.listener.subscription.SubscriptionResultListener;
import com.socialize.log.SocializeLogger;
import com.socialize.notifications.SubscriptionType;
import com.socialize.ui.dialog.SimpleDialogFactory;
import com.socialize.ui.header.SocializeHeader;
import com.socialize.ui.image.ImageLoader;
import com.socialize.ui.profile.UserSettings;
import com.socialize.ui.slider.ActionBarSliderFactory;
import com.socialize.ui.slider.ActionBarSliderFactory.ZOrder;
import com.socialize.ui.slider.ActionBarSliderView;
import com.socialize.ui.util.CompatUtils;
import com.socialize.ui.view.CustomCheckbox;
import com.socialize.ui.view.LoadingListView;
import com.socialize.util.*;
import com.socialize.view.BaseView;
import java.util.List;
public class CommentListView extends BaseView {
private int defaultGrabLength = 30;
private int iconSize = 100;
private IBeanFactory<CommentAdapter> commentAdapterFactory;
private CommentAdapter commentAdapter;
private boolean loading = true; // Default to true
private boolean headerDisplayed = true;
private Entity entity;
private int startIndex = 0;
private int endIndex = defaultGrabLength;
private SocializeLogger logger;
private SimpleDialogFactory<ProgressDialog> progressDialogFactory;
private Drawables drawables;
private AppUtils appUtils;
private DisplayUtils displayUtils;
private CommentUtilsProxy commentUtils;
private SubscriptionUtilsProxy subscriptionUtils;
private UserUtilsProxy userUtils;
private ProgressDialog dialog = null;
private SocializeConfig config;
private IBeanFactory<SocializeHeader> commentHeaderFactory;
private IBeanFactory<CommentEditField> commentEditFieldFactory;
private IBeanFactory<LoadingListView> commentContentViewFactory;
private IBeanFactory<CustomCheckbox> notificationEnabledOptionFactory;
private CommentEditField commentEntryField;
private SocializeHeader header;
private LoadingListView content;
private String customHeaderText;
private boolean showCommentCountInHeader = true;
private IBeanFactory<CommentEntrySliderItem> commentEntryFactory;
private ActionBarSliderView commentEntrySlider;
private ActionBarSliderFactory<ActionBarSliderView> sliderFactory;
private RelativeLayout layoutAnchor;
private ViewGroup sliderAnchor;
private CustomCheckbox notifyBox;
private ImageLoader imageLoader;
private CommentEntrySliderItem commentEntrySliderItem;
private OnCommentViewActionListener onCommentViewActionListener;
public CommentListView(Context context) {
super(context);
}
public void init() {
commentAdapter = commentAdapterFactory.getBean();
LayoutParams fill = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);
setOrientation(LinearLayout.VERTICAL);
setLayoutParams(fill);
CompatUtils.setBackgroundDrawable(this, drawables.getDrawable("crosshatch.png", true, true, true));
setPadding(0, 0, 0, 0);
boolean landscape = displayUtils.isLandscape();
iconSize = displayUtils.getDIP(iconSize);
layoutAnchor = new RelativeLayout(getContext());
LayoutParams innerParams = new LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);
layoutAnchor.setLayoutParams(innerParams);
LinearLayout top = new LinearLayout(getContext());
LinearLayout middle = new LinearLayout(getContext());
sliderAnchor = new LinearLayout(getContext());
int topId = getNextViewId(getParentView());
int middleId = getNextViewId(getParentView());
int bottomId = getNextViewId(getParentView());
top.setPadding(0, 0, 0, 0);
middle.setPadding(0, 0, 0, 0);
sliderAnchor.setPadding(0, 0, 0, 0);
top.setId(topId);
middle.setId(middleId);
sliderAnchor.setId(bottomId);
RelativeLayout.LayoutParams topParams = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
RelativeLayout.LayoutParams middleParams = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);
RelativeLayout.LayoutParams bottomParams = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
topParams.setMargins(0, 0, 0, 0);
middleParams.setMargins(0, 0, 0, 0);
bottomParams.setMargins(0, 0, 0, 0);
topParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
bottomParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
middleParams.addRule(RelativeLayout.BELOW, topId);
middleParams.addRule(RelativeLayout.ABOVE, bottomId);
top.setLayoutParams(topParams);
middle.setLayoutParams(middleParams);
sliderAnchor.setLayoutParams(bottomParams);
if(!landscape && config.isShowCommentHeader() && headerDisplayed) {
header = commentHeaderFactory.getBean();
}
commentEntryField = commentEditFieldFactory.getBean();
content = commentContentViewFactory.getBean();
if(commentEntryFactory != null) {
commentEntrySliderItem = commentEntryFactory.getBean(getCommentAddButtonListener());
}
boolean notificationsAvailable = appUtils.isNotificationsAvailable(getContext());
if(notificationsAvailable) {
notifyBox = notificationEnabledOptionFactory.getBean();
notifyBox.setEnabled(false); // Start disabled
notifyBox.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doNotificationStatusSave();
}
});
notifyBox.setVisibility(View.GONE);
try {
UserSettings user = userUtils.getUserSettings(getContext());
if(user.isNotificationsEnabled()) {
notifyBox.setVisibility(View.VISIBLE);
}
}
catch (SocializeException e) {
if(logger != null) {
logger.error("Error getting user settings", e);
}
else {
e.printStackTrace();
}
}
sliderAnchor.addView(notifyBox);
}
content.setListAdapter(commentAdapter);
content.setScrollListener(getCommentScrollListener());
if(header != null) {
top.addView(header);
}
middle.addView(content);
sliderAnchor.addView(commentEntryField);
layoutAnchor.addView(top);
layoutAnchor.addView(middle);
layoutAnchor.addView(sliderAnchor);
addView(layoutAnchor);
setDefaultGrabLength(ConfigUtils.getConfig(getContext()).getIntProperty("comment.page.size", 20));
}
protected CommentScrollListener getCommentScrollListener() {
return new CommentScrollListener(new CommentScrollCallback() {
@Override
public void onGetNextSet() {
getNextSet();
}
@Override
public boolean isLoading() {
return loading;
}
@Override
public boolean hasMoreItems() {
return !commentAdapter.isLast();
}
});
}
protected CommentAddButtonListener getCommentAddButtonListener() {
return new CommentAddButtonListener(new CommentButtonCallback() {
@Override
public void onError(Context context, SocializeException e) {
showError(getContext(), e);
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onError(e);
}
}
@Override
public void onCancel() {
if(commentEntrySlider != null) {
commentEntrySlider.close();
}
}
@Override
public void onComment(String text, boolean shareLocation, boolean subscribe) {
text = StringUtils.replaceNewLines(text, 3, 2);
if(progressDialogFactory != null) {
dialog = progressDialogFactory.show(getContext(), I18NConstants.DLG_COMMENT, I18NConstants.PLEASE_WAIT);
}
CommentOptions options = newShareOptions();
options.setSubscribeToUpdates(subscribe);
options.setShowAuthDialog(true);
options.setShowShareDialog(true);
commentUtils.addComment(CommentListView.this.getActivity(), entity, text, options, getCommentAddListener(subscribe));
// Won't persist.. but that's ok.
SocializeSession session = getSocialize().getSession();
if(session != null && session.getUserSettings() != null) {
session.getUserSettings().setLocationEnabled(shareLocation);
}
}
});
}
protected CommentAddListener getCommentAddListener(final boolean subscribe) {
return new CommentAddListener() {
@Override
public void onError(SocializeException error) {
showError(getContext(), error);
if(dialog != null) {
dialog.dismiss();
}
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onError(error);
}
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().getPostCommentButton().setEnabled(true);
}
}
@Override
public void onCreate(Comment entity) {
List<Comment> comments = commentAdapter.getComments();
if(comments != null) {
comments.add(0, entity);
}
startIndex++;
endIndex++;
if(commentEntrySlider != null) {
commentEntrySlider.clearContent();
commentEntrySlider.close();
}
commentAdapter.setTotalCount(commentAdapter.getTotalCount() + 1);
commentAdapter.notifyDataSetChanged();
setHeaderText();
content.scrollToTop();
if(dialog != null) {
dialog.dismiss();
}
if(notifyBox != null) {
notifyBox.setChecked(subscribe);
}
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onPostComment(entity);
}
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().getPostCommentButton().setEnabled(true);
}
}
@Override
public void onCancel() {
if(dialog != null) {
dialog.dismiss();
}
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().getPostCommentButton().setEnabled(true);
}
}
};
}
public void reload() {
content.showLoading();
commentAdapter.reset();
// We have to re-set the adapter.. otherwise we get crazy scrolling behavior
// http://support.getsocialize.com/socialize/topics/problems_rendering_of_chat_room_using_android_2_8_2?utm_content=topic_link&utm_medium=email&utm_source=reply_notification
content.setListAdapter(commentAdapter);
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onReload(this);
}
doListComments(true);
}
public CommentAdapter getCommentAdapter() {
return commentAdapter;
}
public void doListComments(final boolean update) {
startIndex = 0;
endIndex = defaultGrabLength;
loading = true;
final List<Comment> comments = commentAdapter.getComments();
if(update || comments == null || comments.size() == 0) {
commentUtils.getCommentsByEntity(getActivity(), entity.getKey(),
startIndex,
endIndex, new CommentListListener() {
@Override
public void onError(SocializeException error) {
showError(getContext(), error);
content.showList();
if(dialog != null) {
dialog.dismiss();
}
loading = false;
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onError(error);
}
}
@Override
public void onList(ListResult<Comment> entities) {
if(entities != null) {
int totalCount = entities.getTotalCount();
List<Comment> items = entities.getItems();
commentAdapter.setComments(items);
commentAdapter.setTotalCount(totalCount);
setHeaderText();
if(totalCount <= endIndex) {
commentAdapter.setLast(true);
}
if(update || comments == null || comments.size() == 0) {
content.scrollToTop();
}
commentAdapter.notifyDataSetChanged();
}
content.showList();
loading = false;
if(onCommentViewActionListener != null && entities != null) {
onCommentViewActionListener.onCommentList(CommentListView.this, entities.getItems(), startIndex, endIndex);
}
if(dialog != null) dialog.dismiss();
}
});
}
else {
content.showList();
setHeaderText();
commentAdapter.notifyDataSetChanged();
if(dialog != null) {
dialog.dismiss();
}
loading = false;
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onCommentList(CommentListView.this, comments, startIndex, endIndex);
}
}
}
// SO we can mock
protected Comment newComment() {
return new Comment();
}
protected void setHeaderText() {
if(header != null) {
String name = (customHeaderText == null) ? entity.getName() : customHeaderText;
if(StringUtils.isEmpty(name)) {
if(showCommentCountInHeader) {
header.setText(commentAdapter.getTotalCount() + " Comments");
}
}
else {
if(showCommentCountInHeader) {
header.setText(name + " (" + commentAdapter.getTotalCount() + ")");
}
else {
header.setText(name);
}
}
}
}
protected void doNotificationStatusSave() {
notifyBox.showLoading();
if(notifyBox.isChecked()) {
subscriptionUtils.subscribe(getActivity(), entity, SubscriptionType.NEW_COMMENTS, new SubscriptionResultListener() {
@Override
public void onError(SocializeException error) {
showError(getContext(), error);
notifyBox.setChecked(false);
notifyBox.hideLoading();
}
@Override
public void onCreate(Subscription entity) {
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().setNotifySubscribeState(true);
}
notifyBox.hideLoading();
}
});
}
else {
subscriptionUtils.unsubscribe(getActivity(), entity, SubscriptionType.NEW_COMMENTS, new SubscriptionResultListener() {
@Override
public void onError(SocializeException error) {
showError(getContext(), error);
notifyBox.setChecked(true);
notifyBox.hideLoading();
}
@Override
public void onCreate(Subscription entity) {
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().setNotifySubscribeState(false);
}
notifyBox.hideLoading();
}
});
}
}
protected void doNotificationStatusLoad() {
if(notifyBox != null) {
notifyBox.showLoading();
// Now load the subscription status for the user
subscriptionUtils.isSubscribed(getActivity(), entity, SubscriptionType.NEW_COMMENTS, new SubscriptionCheckListener() {
@Override
public void onSubscribed(Subscription subscription) {
notifyBox.setChecked(subscription.isSubscribed());
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().setNotifySubscribeState(subscription.isSubscribed());
}
notifyBox.hideLoading();
}
@Override
public void onNotSubscribed() {
notifyBox.setChecked(false);
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().setNotifySubscribeState(true); // Default to true
}
notifyBox.hideLoading();
}
@Override
public void onError(SocializeException error) {
notifyBox.setChecked(false);
if(logger != null) {
logger.error("Error retrieving subscription info", error);
}
else {
SocializeLogger.e(error.getMessage(), error);
}
if(commentEntrySliderItem != null) {
commentEntrySliderItem.getCommentEntryView().setNotifySubscribeState(true); // Default to true
}
notifyBox.hideLoading();
}
});
}
}
public void getNextSet() {
if(logger != null && logger.isDebugEnabled()) {
logger.debug("getNextSet called on CommentListView");
}
loading = true; // Prevent continuous load
startIndex = endIndex;
endIndex+=defaultGrabLength;
int totalCount = commentAdapter.getTotalCount();
if(endIndex > totalCount) {
endIndex = totalCount;
if(startIndex >= endIndex) {
commentAdapter.setLast(true);
commentAdapter.notifyDataSetChanged();
loading = false;
return;
}
}
commentUtils.getCommentsByEntity(getActivity(), entity.getKey(),
startIndex,
endIndex,
new CommentListListener() {
@Override
public void onError(SocializeException error) {
// Don't show loading anymore
if(logger != null) {
logger.error("Error retrieving comments", error);
}
else {
SocializeLogger.e(error.getMessage(), error);
}
loading = false;
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onError(error);
}
}
@Override
public void onList(ListResult<Comment> entities) {
List<Comment> comments = commentAdapter.getComments();
if(entities != null) {
comments.addAll(entities.getItems());
preLoadImages(comments);
}
commentAdapter.setComments(comments);
commentAdapter.notifyDataSetChanged();
loading = false;
if(onCommentViewActionListener != null && entities != null) {
onCommentViewActionListener.onCommentList(CommentListView.this, comments, startIndex, endIndex);
}
}
});
}
protected void preLoadImages(List<Comment> comments) {
if(comments != null) {
for (Comment comment : comments) {
User user = comment.getUser();
if(user != null) {
String imageUrl = user.getSmallImageUri();
if(!StringUtils.isEmpty(imageUrl)) {
CacheableDrawable cached = drawables.getCache().get(imageUrl);
if(cached == null || cached.isRecycled()) {
imageLoader.loadImageByUrl(imageUrl, iconSize, iconSize, null);
}
}
}
}
}
}
@Override
public void onViewLoad() {
super.onViewLoad();
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onCreate(this);
}
if(commentAdapter != null && onCommentViewActionListener != null) {
commentAdapter.setOnCommentViewActionListener(onCommentViewActionListener);
}
}
@Override
public void onViewRendered(int width, int height) {
if(sliderFactory != null) {
if(commentEntrySlider == null) {
commentEntrySlider = sliderFactory.wrap(getSliderAnchor(), ZOrder.FRONT, height);
}
}
if(commentEntrySliderItem != null) {
commentEntrySlider.loadItem(commentEntrySliderItem);
commentEntryField.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(commentEntrySlider != null) {
commentEntrySlider.showSliderItem(commentEntrySliderItem);
}
}
});
}
else if(commentEntryField != null) {
commentEntryField.setVisibility(GONE);
}
if(getSocialize().isAuthenticated()) {
doListComments(false);
doNotificationStatusLoad();
}
else {
SocializeException e = new SocializeException("Socialize not authenticated");
showError(getContext(),e);
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onError(e);
}
if(content != null) {
content.showList();
}
}
if(onCommentViewActionListener != null) {
onCommentViewActionListener.onRender(this);
}
}
public void setCommentAdapter(CommentAdapter commentAdapter) {
this.commentAdapter = commentAdapter;
}
public void setLogger(SocializeLogger logger) {
this.logger = logger;
}
public void setProgressDialogFactory(SimpleDialogFactory<ProgressDialog> progressDialogFactory) {
this.progressDialogFactory = progressDialogFactory;
}
public void setDrawables(Drawables drawables) {
this.drawables = drawables;
}
public void setDefaultGrabLength(int defaultGrabLength) {
this.defaultGrabLength = defaultGrabLength;
}
public void setCommentHeaderFactory(IBeanFactory<SocializeHeader> commentHeaderFactory) {
this.commentHeaderFactory = commentHeaderFactory;
}
public void setCommentEditFieldFactory(IBeanFactory<CommentEditField> commentEditFieldFactory) {
this.commentEditFieldFactory = commentEditFieldFactory;
}
public void setCommentContentViewFactory(IBeanFactory<LoadingListView> commentContentViewFactory) {
this.commentContentViewFactory = commentContentViewFactory;
}
public void setAppUtils(AppUtils appUtils) {
this.appUtils = appUtils;
}
public void setNotificationEnabledOptionFactory(IBeanFactory<CustomCheckbox> notificationEnabledOptionFactory) {
this.notificationEnabledOptionFactory = notificationEnabledOptionFactory;
}
public Entity getEntity() {
return entity;
}
public void setEntity(Entity entity) {
this.entity = entity;
}
public boolean isLoading() {
return loading;
}
protected void setLoading(boolean loading) {
this.loading = loading;
}
protected void setCommentEntryField(CommentEditField field) {
this.commentEntryField = field;
}
protected void setHeader(SocializeHeader header) {
this.header = header;
}
protected void setContent(LoadingListView content) {
this.content = content;
}
protected void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
protected void setEndIndex(int endIndex) {
this.endIndex = endIndex;
}
public int getStartIndex() {
return startIndex;
}
public int getEndIndex() {
return endIndex;
}
public void setCommentEntryFactory(IBeanFactory<CommentEntrySliderItem> commentEntryFactory) {
this.commentEntryFactory = commentEntryFactory;
}
public int getTotalCount() {
return commentAdapter.getTotalCount();
}
/**
* Called when the current logged in user updates their profile.
*/
public void onProfileUpdate() {
commentAdapter.notifyDataSetChanged();
if(commentEntrySlider != null) {
commentEntrySlider.updateContent();
}
if(notifyBox != null) {
try {
UserSettings user = userUtils.getUserSettings(getContext());
if(user.isNotificationsEnabled()) {
notifyBox.setVisibility(View.VISIBLE);
}
else {
notifyBox.setVisibility(View.GONE);
}
}
catch (SocializeException e) {
if(logger != null) {
logger.error("Error getting user settings", e);
}
else {
e.printStackTrace();
}
notifyBox.setVisibility(View.GONE);
}
}
}
// So we can mock
protected CommentOptions newShareOptions() {
return commentUtils.getUserCommentOptions(getContext());
}
protected RelativeLayout getLayoutAnchor() {
return layoutAnchor;
}
protected ViewGroup getSliderAnchor() {
return sliderAnchor;
}
public void setSliderFactory(ActionBarSliderFactory<ActionBarSliderView> sliderFactory) {
this.sliderFactory = sliderFactory;
}
public void setOnCommentViewActionListener(OnCommentViewActionListener onCommentViewActionListener) {
this.onCommentViewActionListener = onCommentViewActionListener;
if(commentAdapter != null) {
commentAdapter.setOnCommentViewActionListener(onCommentViewActionListener);
}
}
public ActionBarSliderView getCommentEntryViewSlider() {
return commentEntrySlider;
}
public void setImageLoader(ImageLoader imageLoader) {
this.imageLoader = imageLoader;
}
public void setDisplayUtils(DisplayUtils displayUtils) {
this.displayUtils = displayUtils;
}
public void setCommentUtils(CommentUtilsProxy commentUtils) {
this.commentUtils = commentUtils;
}
public void setSubscriptionUtils(SubscriptionUtilsProxy subscriptionUtils) {
this.subscriptionUtils = subscriptionUtils;
}
public void setUserUtils(UserUtilsProxy userUtils) {
this.userUtils = userUtils;
}
public void setConfig(SocializeConfig config) {
this.config = config;
}
public CommentEditField getCommentEntryField() {
return commentEntryField;
}
public String getCustomHeaderText() {
return customHeaderText;
}
public void setCustomHeaderText(String customHeaderText) {
this.customHeaderText = customHeaderText;
}
public boolean isShowCommentCountInHeader() {
return showCommentCountInHeader;
}
public void setShowCommentCountInHeader(boolean showCommentCountInHeader) {
this.showCommentCountInHeader = showCommentCountInHeader;
}
public void setCommentAdapterFactory(IBeanFactory<CommentAdapter> commentAdapterFactory) {
this.commentAdapterFactory = commentAdapterFactory;
}
public SocializeHeader getHeader() {
return header;
}
public LoadingListView getContent() {
return content;
}
public void setHeaderDisplayed(boolean showHeader) {
this.headerDisplayed = showHeader;
if(header != null) {
if(headerDisplayed) {
header.setVisibility(View.VISIBLE);
}
else {
header.setVisibility(View.GONE);
}
}
}
}