Page 1 of 1

Create a "like" button, which only counts up once

Posted: Fri May 15, 2020 9:21 am
by Kinmoku
Hi all,
I want to create a button which displays at the side of a chat post which acts as a "like" button i.e. it can only be pushed once and adds 1 to the number shown.

My code so far... Screens:

Code: Select all

screen chat_picture(pic=None, nick=None, avatar=None, posttime=None):
    hbox:
        spacing 10
        if avatar != None:
            add avatar
        vbox:
            hbox:
                if nick != None:
                    text nick
                    
                if posttime != None:
                    text " - "
                    text posttime
                    
                if nick != None and pic != None:
                    null height 10
                    
            if pic != None:
                   add pic
                
        vbox:
            yalign 1.0
            spacing 8
            button:
                background "images/button_likes.png"
                text "{color=#000}1{/color}" xpos 54 ypos -5 ### this is the button I want to change. So far, it doesn't have an action.
How the chat works in script:

Code: Select all

    $ fflog.add_chat(msg="This is a message I want to like.", nick="Wolfie", avatar="images/avatars/wolfie.png", posttime="< 1 hour ago")
Not only am I unsure how to create the button and change the text on it, but each post will have a different amount of likes as well (which I'd like to set with $ fflog.add_chat). So, without making a different like button for every post, I'm unsure how to go about this, too.

Here's the rest of the chat code for reference:

Code: Select all

screen chat_log(log):
    viewport id "chatlog":
        xpos 332
        ypos 144
        ysize 900
        yadjustment log.adjustment()
        mousewheel True
        draggable True
        yinitial 1.0
        python:
            # Thanks to mangoduck at
            # https://lemmasoft.renai.us/forums/viewtopic.php?t=32584 for this
            # flash of insight for auto scrolling
            log.adjustment().value = chat_infinity_float
        vbox:
            spacing 20

            for type, kwargs in log.history():
                use expression type pass (**kwargs)
                
#...


define chat_infinity_float = float("inf")
init python:
    class ChatLog:
        """
        Thanks to milkymalk at
        https://lemmasoft.renai.us/forums/viewtopic.php?t=44711
        for the idea here. I refined the implementation a bunch, but it's their
        core suggestion that helped.
        """
        def __init__(self):
            # Create a blank list for the chats.
            self._chats = []
            # And make the adjustment for our screen.
            self._adj = ui.adjustment()
        def add_chat(self, type="chat_entry", **kwargs):
            """
            Adds a new chat entry.

            type - selects the name of the screen that will display this line
                of chat.

            Additional named arguments will need to be provided based on the
            arguments the screen that displays the line. For the default
            chat_entry screen, this will be msg, nick, and avatar.

            For example:
                mychat.add_chat(type="chat_entry", msg="Hello world",
                    nick="darkflamemaster", avatar="dfm chat avatar")
            """
            self._chats.append((type, kwargs))
            return len(self._chats)-1
        def history(self):
            """ Returns the list of chat lines. """
            return self._chats
        def adjustment(self):
            """ Returns the adjustment. Needed by the chat log screen """
            return self._adj;
Does anyone have any ideas? :)

Re: Create a "like" button, which only counts up once

Posted: Sat May 16, 2020 4:28 am
by Alex
Try to add one more property to chat object to track if player liked it or not. So, if player haven't liked it yet, button will add 1 to likes, otherwise subtract 1.

Re: Create a "like" button, which only counts up once

Posted: Sun May 17, 2020 7:59 am
by gas
As suggested, pass other arguments.

For example:
mychat.add_chat(type="chat_entry", msg="Hello world", nick="darkflamemaster", avatar="dfm chat avatar", likes = 3, liked = False)

and this should do the trick:

Code: Select all

screen chat_picture(pic=None, nick=None, avatar=None, posttime=None, likes = 0, liked = False):
    hbox:
        spacing 10
        if avatar != None:
            add avatar
        vbox:
            hbox:
                if nick != None:
                    text nick
                    
                if posttime != None:
                    text " - "
                    text posttime
                    
                if nick != None and pic != None:
                    null height 10
                    
            if pic != None:
                   add pic
                
        vbox:
            yalign 1.0
            spacing 8
            button:
                background "images/button_likes.png"
                text "{color=#000}[likes]{/color}" xpos 54 ypos -5 action [If(liked, true = SetVariable("likes", likes-1), false = SetVariable("likes",likes +1)), ToggleVariable("liked")]

The action is incredibly contrived but does:
IF-- liked is True, do true action (remove 1 likes)
IF--liked is False, do the false action (add 1 likes)
THEN
Toggle the liked flag.

I didn't tested it obviously but should work.

Re: Create a "like" button, which only counts up once

Posted: Mon May 18, 2020 4:41 am
by Kinmoku
gas wrote: Sun May 17, 2020 7:59 am As suggested, pass other arguments.

For example:
mychat.add_chat(type="chat_entry", msg="Hello world", nick="darkflamemaster", avatar="dfm chat avatar", likes = 3, liked = False)

and this should do the trick:

Code: Select all

screen chat_picture(pic=None, nick=None, avatar=None, posttime=None, likes = 0, liked = False):
    hbox:
        spacing 10
        if avatar != None:
            add avatar
        vbox:
            hbox:
                if nick != None:
                    text nick
                    
                if posttime != None:
                    text " - "
                    text posttime
                    
                if nick != None and pic != None:
                    null height 10
                    
            if pic != None:
                   add pic
                
        vbox:
            yalign 1.0
            spacing 8
            button:
                background "images/button_likes.png"
                text "{color=#000}[likes]{/color}" xpos 54 ypos -5 action [If(liked, true = SetVariable("likes", likes-1), false = SetVariable("likes",likes +1)), ToggleVariable("liked")]

The action is incredibly contrived but does:
IF-- liked is True, do true action (remove 1 likes)
IF--liked is False, do the false action (add 1 likes)
THEN
Toggle the liked flag.

I didn't tested it obviously but should work.
Cool, so this will also unlike something if it's clicked again. That's great :)

Unfortunately, when I add the additional code, I get an error:

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/script.rpy", line 246, in script
    pause 1
  File "renpy/common/000statements.rpy", line 414, in execute_pause
    renpy.with_statement(Pause(delay))
  File "renpy/common/00action_data.rpy", line 79, in get_selected
    return __get_field(self.object, self.field, self.kind) == self.value
  File "renpy/common/00action_data.rpy", line 39, in _m1_00action_data__get_field
    raise NameError("The {} {} does not exist.".format(kind, name))
NameError: The variable likes does not exist.

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/script.rpy", line 246, in script
    pause 1
  File "/Applications/renpy-6.99.11-sdk/renpy/ast.py", line 1949, in execute
    self.call("execute")
  File "/Applications/renpy-6.99.11-sdk/renpy/ast.py", line 1937, in call
    return renpy.statements.call(method, parsed, *args, **kwargs)
  File "/Applications/renpy-6.99.11-sdk/renpy/statements.py", line 277, in call
    return method(parsed, *args, **kwargs)
  File "renpy/common/000statements.rpy", line 414, in execute_pause
    renpy.with_statement(Pause(delay))
  File "/Applications/renpy-6.99.11-sdk/renpy/exports.py", line 1601, in with_statement
    return renpy.game.interface.do_with(trans, paired, clear=clear)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 2251, in do_with
    clear=clear)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 2702, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, **kwargs)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 3094, in interact_core
    root_widget.visit_all(lambda i : i.per_interact())
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/screen.py", line 434, in visit_all
    self.child.visit_all(callback, seen=None)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 541, in visit_all
    d.visit_all(callback, seen)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 543, in visit_all
    callback(self)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/core.py", line 3094, in <lambda>
    root_widget.visit_all(lambda i : i.per_interact())
  File "/Applications/renpy-6.99.11-sdk/renpy/display/behavior.py", line 857, in per_interact
    if self.is_selected():
  File "/Applications/renpy-6.99.11-sdk/renpy/display/behavior.py", line 845, in is_selected
    return is_selected(self.action)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/behavior.py", line 388, in is_selected
    return any(is_selected(i) for i in action)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/behavior.py", line 388, in <genexpr>
    return any(is_selected(i) for i in action)
  File "/Applications/renpy-6.99.11-sdk/renpy/display/behavior.py", line 391, in is_selected
    return action.get_selected()
  File "renpy/common/00action_data.rpy", line 79, in get_selected
    return __get_field(self.object, self.field, self.kind) == self.value
  File "renpy/common/00action_data.rpy", line 39, in _m1_00action_data__get_field
    raise NameError("The {} {} does not exist.".format(kind, name))
NameError: The variable likes does not exist.

Darwin-17.7.0-x86_64-i386-64bit
Ren'Py 7.3.5.606

Here's my code:

Code: Select all

    $ fflog.add_chat(msg="This is a message I want to like.", nick="Wolfie", avatar="images/avatars/wolfie.png", posttime="< 1 hour ago", likes=2, liked = False)

Code: Select all

screen chat_entry(msg="", nick=None, avatar=None, posttime=None, likes=0, liked=False):
    hbox:
        spacing 40
        xmaximum 1300
        
        if avatar != None:
            add avatar
        vbox:
            hbox:
                if nick != None:
                    text nick
                    
                if posttime != None:
                    text " - "
                    text posttime
               
            text msg
            
        vbox:
            yalign 1.0
            spacing 8
            button:
                background "images/button_likes.png"
                text "{color=#000}[likes]{/color}" xpos 54 ypos -5
                action [If(liked, true = SetVariable("likes", likes-1), false = SetVariable("likes",likes +1)), ToggleVariable("liked")]
Do I need to define "likes" somewhere else?

Re: Create a "like" button, which only counts up once

Posted: Wed May 20, 2020 10:54 am
by gas
Yes, my wrong, I didn't understood that you're calling an object as the screen parameter.

I'll STRONGLY suggest you to make a copy of the original script and use a copy with these changes, as I can't predict what will happen and probably you want a quick way to restore the originals.

So...
It's a bit more complicated than this.
You should rewrite the thing from scratch, to add actual objects and not just a list to your ChatLog
So.

Code: Select all

define chat_infinity_float = float("inf")
init python:
    class ChatLog:
        def __init__(self):
            # Create a blank list for the chats.
            self._chats = []
            # And make the adjustment for our screen.
            self._adj = ui.adjustment()
        def add_chat(self, what):
            self._chats.append(what)
            return len(self._chats)-1
        def history(self):
            """ Returns the list of chat lines. """
            return self._chats
        def adjustment(self):
            """ Returns the adjustment. Needed by the chat log screen """
            return self._adj;

    class Chat(object):
        def __init__(self, type = "chat_entry", pic=None, nick=None, avatar=None, msg = None, posttime=None, likes = 0, liked = False):
            self.type = type
            self.pic = pic
            self.nick = nick
            self.avatar = avatar
            self.msg = msg
            self.posttime = posttime
            self.likes = likes
            self.liked = liked

Now, to add a new chat you must do:
$ fflog.add_chat( Chat(*parameters*) )

Change the screens this way:

Code: Select all

screen chat_log(log):
    viewport id "chatlog":
        xpos 332
        ypos 144
        ysize 900
        yadjustment log.adjustment()
        mousewheel True
        draggable True
        yinitial 1.0
        python:
            log.adjustment().value = chat_infinity_float
        vbox:
            spacing 20

            for i in log.history():
                use expression i.type pass (i)

Code: Select all

screen chat_entry(obj = None):
    hbox:
        spacing 40
        xmaximum 1300
        
        if obj.avatar != None:
            add obj.avatar
        vbox:
            hbox:
                if obj.nick != None:
                    text obj.nick
                    
                if obj.posttime != None:
                    text " - "
                    text obj.posttime
               
            text obj.msg
            
        vbox:
            yalign 1.0
            spacing 8
            button:
                background "images/button_likes.png"
                text "{color=#000}[obj.likes]{/color}" xpos 54 ypos -5
                action [If(obj.liked, true = SetFiel(obj, "likes", likes-1), false = SetField(obj, "likes",likes +1)), ToggleField(obj, "liked")]
Let me know if that did the trick.