Reputation: 385
Coming here from backendless support forum. "This support forum is strictly for Backendless-related issues. Any general problems outside of our APIs and backend services are not covered by support. Please consider posting to stackoverflow.com and/or Android forums." Mark Piller.
So I'm posting my problem here. At backendless support forum I got some precious help to save and retrieve relations but now I'm facing another problem with the Like button. I'm working on a social app in which there are 3 button: Like Comment Share. Link at my backendless support thread: http://support.backendless.com/topic/some-questions-regarding-data-loading-in-recyclerview-android For now I'm trying to make Like button work but I'm facing the following problem:
If you look at the following code and at the screenshot I attached you can see that there's the like heart button which isn't fill and it means I didn't hit the like for that post. And at 2 number there's another button which is filled and I hit liked on it and the app added me to the list of users those like that post.
if (user.getObjectId().equals(userId)) {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_on);
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showToast();
}
});
} else {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_off);
//onclick in another function: setLike(holder.like,holder.likes,feeds);
}
But the problem is that the click on the empty heart isn't working. I tried to create a toast to check if click works and the toast isn't showing up.
But if I click on an item which I liked (with heart icon filled) it shows me the toast which I put to check if it listens to my click....
I tried to debug the app and nothing appears in the debug window... everything seems to be normal but can't find out what's the problem with the code. My Adapter class is following:
public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.FeedsHolder> {
private List<Feeds> list;
private Context context;
private static String TAG = "MainActivity";
public FeedAdapter(Context context, List<Feeds> list) {
this.context = context;
this.list = list;
}
@Override
public FeedsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_item, parent, false);
return new FeedsHolder(view);
}
@Override
public void onBindViewHolder(final FeedsHolder holder, int position) {
//Starting Feeds
final Feeds feeds = list.get(position);
//Name
holder.name.setText(feeds.getOwner());
//Profile picture
holder.profilePictureURL = feeds.getProfilePictureURL();
//Image
holder.imageURL = feeds.getImageUrl();
//Getting date
Date myD = feeds.getCreated();
long ddate = myD.getTime();
String myDate = String.valueOf(DateUtils.getRelativeTimeSpanString(ddate, System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS));
holder.timeAgo.setText("• " + myDate);
//Get total likes
final int i = feeds.getLikes();
//Query
QueryOptions options = new QueryOptions();
options.setRelated( Arrays.asList( "usersThatLike" ) );
BackendlessDataQuery query = new BackendlessDataQuery();
query.setQueryOptions( options );
// getting all saved feeds with related users
Backendless.Data.of(Feeds.class).find(query, new AsyncCallback<BackendlessCollection<Feeds>>() {
@Override
public void handleResponse(BackendlessCollection<Feeds> response) {
String userId = Backendless.UserService.CurrentUser().getObjectId();
for (Feeds feed: response.getCurrentPage()) {
List<BackendlessUser> likedUsers = feeds.getUsersThatLike();
for (BackendlessUser user : likedUsers)
if (user.getObjectId().equals(userId)) {
Log.d(TAG, "No -------------------------------------");
holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "You already like this item", Toast.LENGTH_SHORT).show();
}
});
} else {
holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_off));
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "It should work +++++++++++++++++++++++++++++++");
// getting current user
Toast.makeText(context, "Arrived", Toast.LENGTH_SHORT).show();
BackendlessUser currentUser = Backendless.UserService.CurrentUser();
// adding current user as one who "liked" feed, you should implement "adding" by yourself
List<BackendlessUser> list = new ArrayList<>();
list.add(currentUser);
feeds.setUsersThatLike(list);
holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
feeds.setLikes(i + 1);
Backendless.Data.of(Feeds.class).save(feeds, new AsyncCallback<Feeds>() {
@Override
public void handleResponse(Feeds feeds) {
int likes = feeds.getLikes();
if (likes == 1) {
holder.likes.setText(i + 1 + " like");
} else {
holder.likes.setText(i + 1 + " likes");
}
}
@Override
public void handleFault(BackendlessFault backendlessFault) {
}
});
}
});
}
}
}
@Override
public void handleFault(BackendlessFault backendlessFault) {
}
});
holder.status.setText(feeds.getStatus());
String thisString = "no";
String myImageString = "no";
Picasso.with(context).load(holder.profilePictureURL).placeholder(R.drawable.placeholder).into(holder.profilePicture);
String image = feeds.getIsImageUrlEmpty();
if (!image.equals(myImageString)) {
holder.image.setVisibility(View.GONE);
holder.tagStatusBottom.setVisibility(View.VISIBLE);
holder.tagImageBottom.setVisibility(View.GONE);
} else {
holder.image.setVisibility(View.VISIBLE);
holder.tagStatusBottom.setVisibility(View.GONE);
holder.tagImageBottom.setVisibility(View.VISIBLE);
Picasso.with(context).load(holder.imageURL).placeholder(R.drawable.placeholder).into(holder.image);
}
String myString = feeds.getIsTagEmpty();
if (myString.equals(thisString)){
holder.tagImageBottom.setVisibility(View.VISIBLE);
if (!image.equals(myImageString)) {
holder.image.setVisibility(View.GONE);
holder.tagStatusBottom.setVisibility(View.VISIBLE);
holder.tagImageBottom.setVisibility(View.GONE);
} else {
holder.image.setVisibility(View.VISIBLE);
holder.tagStatusBottom.setVisibility(View.GONE);
holder.tagImageBottom.setVisibility(View.VISIBLE);
Picasso.with(context).load(holder.imageURL).placeholder(R.drawable.placeholder).into(holder.image);
}
} else {
holder.tagImageBottom.setVisibility(View.GONE);
holder.tagStatusBottom.setVisibility(View.GONE);
}
String str = feeds.getTag();
ArrayList<int[]> hashtagSpans1 = getSpans(str, '#');
SpannableString commentsContent1 =
new SpannableString(str);
setSpanComment(commentsContent1, hashtagSpans1) ;
holder.tagImageBottom.setText(commentsContent1);
holder.tagStatusBottom.setText(commentsContent1);
holder.tagImageBottom.setMovementMethod(LinkMovementMethod.getInstance());
int likes = feeds.getLikes();
if (likes == 1) {
holder.likes.setText(i +" like");
} else {
holder.likes.setText(i +" likes");
}
}
public ArrayList<int[]> getSpans(String body, char prefix) {
ArrayList<int[]> spans = new ArrayList<int[]>();
Pattern pattern = Pattern.compile(prefix + "\\w+");
Matcher matcher = pattern.matcher(body);
// Check all occurrences
while (matcher.find()) {
int[] currentSpan = new int[2];
currentSpan[0] = matcher.start();
currentSpan[1] = matcher.end();
spans.add(currentSpan);
}
return spans;
}
private void setSpanComment(SpannableString commentsContent, ArrayList<int[]> hashtagSpans) {
for(int i = 0; i < hashtagSpans.size(); i++) {
int[] span = hashtagSpans.get(i);
int hashTagStart = span[0];
int hashTagEnd = span[1];
commentsContent.setSpan(new Hashtag(context),
hashTagStart,
hashTagEnd, 0);
}
}
@Override
public int getItemCount() {
return list.size();
}
And here is my Feed class:
public class Feeds
{
private String owner;
private String tag;
private String profilePictureURL;
private String imageURL;
private Date created;
private Date updated;
private String status;
private int likes;
private String isTagEmpty;
private String isImageUrlEmpty;
private List<BackendlessUser> usersThatLike;
public String getOwner()
{
return owner;
}
public void setOwner( String owner )
{
this.owner = owner;
}
public int getLikes()
{
return likes;
}
public void setLikes ( int likes )
{
this.likes = likes;
}
public String getIsTagEmpty()
{
return isTagEmpty;
}
public void setIsTagEmpty ( String isTagEmpty )
{
this.isTagEmpty = isTagEmpty;
}
public String getIsImageUrlEmpty()
{
return isImageUrlEmpty;
}
public void setIsImageUrlEmpty ( String isImageUrlEmpty )
{
this.isImageUrlEmpty = isImageUrlEmpty;
}
public String getStatus()
{
return status;
}
public void setStatus( String status )
{
this.status = status;
}
public String getTag()
{
return tag;
}
public void setTag( String tag )
{
this.tag = tag;
}
public String getProfilePictureURL()
{
return profilePictureURL;
}
public void setProfilePictureURL ( String profilePictureURL )
{
this.profilePictureURL = profilePictureURL;
}
public String getImageUrl()
{
return imageURL;
}
public void setImageUrl ( String imageURL )
{
this.imageURL = imageURL;
}
public Date getCreated()
{
return created;
}
public Date getUpdated()
{
return updated;
}
public List<BackendlessUser> getUsersThatLike() {
return usersThatLike;
}
public void setUsersThatLike(List<BackendlessUser> usersThatLike) {
this.usersThatLike = usersThatLike;
}
}
Can you help me with it?
EDIT: After implementing code in the answer below it doesn't work. This is how I edited my code:
//Skipped previous code. Posted only the changed code
Backendless.Data.of(Feeds.class).find(query, new AsyncCallback<BackendlessCollection<Feeds>>() {
@Override
public void handleResponse(final BackendlessCollection<Feeds> feedsBackendlessCollection) {
//Suggested by sihao
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String userId = Backendless.UserService.CurrentUser().getObjectId();
for (Feeds feed: feedsBackendlessCollection.getCurrentPage()) {
List<BackendlessUser> likedUsers = feeds.getUsersThatLike();
for (BackendlessUser user : likedUsers)
if (user.getObjectId().equals(userId)) {
Toast.makeText(context,"You already liked this item",Toast.LENGTH_SHORT).show();
} else {
// getting current user
BackendlessUser currentUser = Backendless.UserService.CurrentUser();
// adding current user as one who "liked" feed, you should implement "adding" by yourself
List<BackendlessUser> list = new ArrayList<>();
list.add(currentUser);
feeds.setUsersThatLike(list);
holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
feeds.setLikes(i + 1);
Backendless.Data.of(Feeds.class).save(feeds, new AsyncCallback<Feeds>() {
@Override
public void handleResponse(Feeds feeds) {
int likes = feeds.getLikes();
if (likes == 1) {
holder.likes.setText(i + 1 + " like");
} else {
holder.likes.setText(i + 1 + " likes");
}
}
@Override
public void handleFault(BackendlessFault backendlessFault) {
}
});
}
}
}
});
}
@Override
public void handleFault(BackendlessFault backendlessFault) {
}
});
UPDATE: I tried to solve the issue in these days and got an (nice) idea. I'm successfully changing the buttons background from empty heart to fill heart for the elements that has been likes by users. I got the following idea: Check if the heart is empty or fill. So on activity load my app gets data from the "usersThatLike" column and set fill heart drawable if user is present in the list on backendless and empty heart drawable if it isn't there. So now I'm trying to create a check on the drawable. If heart is filled than show the toast "You liked this item already" else put the like to the item and add the user to "usersThatLike" column for current item. But it's returning "filled" heart for all the items. I mean to say, even if the heart drawable is empty it is returning that it's filled and if I click a filled heart drawable than it will show the toast but if the heart isn't filles it will show the same toast: My code is:
//*** Skipped the query code. In handleResponse:
String userId = Backendless.UserService.CurrentUser().getObjectId();
for (Feeds feed: response.getData()) {
feed = list.get(position);
List<BackendlessUser> likedUsers = feed.getUsersThatLike();
for (BackendlessUser user : likedUsers)
if (user.getObjectId().equals(userId)) {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_on);
} else if (!user.getObjectId().equals(userId)) {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_off);
}
}
And than out of the handleResponse, in normal onBindViewHolder after the query code I'm checking the drawable like this:
//***HERE IS THE QUERY
Backendless.Data.of(Feeds.class).find(query, new AsyncCallback<BackendlessCollection<Feeds>>() {
//***SKIPPED FOR BREVITY
});
//***HERE IS THE CHECK
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (holder.like.getBackground() != context.getDrawable(R.drawable.ic_star_rate_off)){
toast();
} else {
setLike();
}
}
});
Upvotes: 0
Views: 330
Reputation: 385
Hello guys, I finally found a great tricky solution to my problem. I was able to save the user to "usersThatLike" column and set the like on the certain item. But every time I clicked like button it was showing the toast "You already liked it" which should be shown only if I was present in the list of usersThatLike so there was the problem. I used the following trick to get rid of this problem: In my RecyclerView adapter I queried my class like this:
QueryOptions options = new QueryOptions();
options.setRelated( Arrays.asList( "usersThatLike" ) );
BackendlessDataQuery query = new BackendlessDataQuery();
query.setQueryOptions( options );
Backendless.Data.of(Feeds.class).find(query, new AsyncCallback<BackendlessCollection<Feeds>>() {
@Override
public void handleResponse(BackendlessCollection<Feeds> response) {
String userId = Backendless.UserService.CurrentUser().getObjectId();
for (Feeds feed: response.getData()) {
feed = list.get(position);
List<BackendlessUser> likedUsers = feed.getUsersThatLike();
for (BackendlessUser user : likedUsers)
if (user.getObjectId().equals(userId)) {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_on);
} else if (!user.getObjectId().equals(userId)) {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_off);
}
}
}
@Override
public void handleFault(BackendlessFault backendlessFault) {
}
});
As you can see I set the drawable with star off if query returns that user isn't in the list and on if the user is there.
So after that here is how I was able to resolve the problem. Outside of my query I created the following check:
holder.likeLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (holder.like.getBackground().getConstantState() != ContextCompat.getDrawable(context, R.drawable.ic_star_rate_off).getConstantState()){
toast();
} else {
setLike();
}
}
});
In code above I get the button background and compare it to the image present in my drawable folder with star off. if the like button is with star_off it will set the like and add user to the usersThatLike list. Otherwise show a toast: "You already liked this item"
Hope it can help others and save their time as I have spent lot of time on this issue.
Regards
Answering to sihao's comment : @sihao if you check my first post you will see:
if (user.getObjectId().equals(userId)) {
Log.d(TAG, "No -------------------------------------");
holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
// FIRST ONCLICK LISTENER
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "You already like this item", Toast.LENGTH_SHORT).show();
}
});
} else {
holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_off));
// SECOND ONCLICK LISTENER
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "It should work +++++++++++++++++++++++++++++++");
// getting current user
Toast.makeText(context, "Arrived", Toast.LENGTH_SHORT).show();
BackendlessUser currentUser = Backendless.UserService.CurrentUser();
// adding current user as one who "liked" feed, you should implement "adding" by yourself
List<BackendlessUser> list = new ArrayList<>();
list.add(currentUser);
feeds.setUsersThatLike(list);
holder.like.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_star_rate_on));
feeds.setLikes(i + 1);
Backendless.Data.of(Feeds.class).save(feeds, new AsyncCallback<Feeds>() {
@Override
public void handleResponse(Feeds feeds) {
int likes = feeds.getLikes();
if (likes == 1) {
holder.likes.setText(i + 1 + " like");
} else {
holder.likes.setText(i + 1 + " likes");
}
}
@Override
public void handleFault(BackendlessFault backendlessFault) {
}
});
}
});
Upvotes: 0
Reputation: 431
I believe your issue lies here.
With reference to your code given above:
//****PART I: NOTICE HERE****//
if (user.getObjectId().equals(userId)) {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_on);
//****YOUR CLICK LISTENER*****//
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showToast();
}
});
//****PART II: NOTICE HERE****//
} else {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_off);
//onclick in another function: setLike(holder.like,holder.likes,feeds);
}
If you look at the two parts indicated Part I and II, you will realize that you have only attached button's ClickListener if the user had liked the post before.
Your solution is to move this ClickListener out of the scope, to somewhere more general.
For example:
//****YOUR CLICK LISTENER*****//
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showToast();
}
});
//****PART I: NOTICE HERE****//
if (user.getObjectId().equals(userId)) {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_on);
//****PART II: NOTICE HERE****//
} else {
holder.like.setBackgroundResource(R.drawable.ic_star_rate_off);
//onclick in another function: setLike(holder.like,holder.likes,feeds);
}
EDIT:
From your code, you seem to be trying to attach two ClickListeners to the same button.
Instead of doing that, you should try this approach.
First, use the modified example I have provided. (Adding a general click listener)
In your ClickListener, implement it this way.
//****YOUR CLICK LISTENER*****//
holder.like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (user.getObjectId().equals(userId)) {
.... do your stuff here
} else {
.... do other stuff here
}
}
});
Upvotes: 1