Asama
Asama

Reputation: 385

Android - Backendless: Issue with like button

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

Answers (2)

Asama
Asama

Reputation: 385

UPDATE:

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


Old Answer:

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

sihao
sihao

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

Related Questions