Recipes for using the RADChatRoom component and customizing it to suit your needs.

1. Customizing Chat Bubbles using CSS

Problem

You want customize the look of the chat bubbles using CSS. E.g. Change the shape, color, border, etc.. of the chat bubble.

Solution

You can use CSS to customize many aspects of the chat room view. You just need to override the styles of the relevant UIIDs in your application’s theme.css stylesheet.

Tip
You can find the "theme.css" file inside the "css" directory of your project.

The relevant UIIDs for the chat bubbles are:

Table 1. Chat Bubble UIIDs
UIID Description

ChatBubbleSpanLabelOwn

The Border/Wrapper around the chat bubbles that the user posts. (I.e. on the right-hand side of the chat room view). Set background, border, padding on this UIID.

ChatBubbleTextOwn

The text inside the chat bubbles that the user posts.

ChatBubbleSpanLabelOther

The Border/Wrapper around the chat bubbles that "other" users post. (I.e. on the left-hand side of the chat room view). Set background, border, padding on this UIID.

ChatBubbleTextOther

The text inside the chat bubbles that other users post.

ChatBubbleTextOtherDesktop

The text inside the chat bubbles that other users post on the desktop.

ChatBubbleTextOwnDesktop

The text inside the chat bubbles that the user posts on the desktop.

Changing The Bubble Color

The default shape of chat bubbles is generated by RoundRect borders. If all you want to do is change the color of the chat bubbles, then you can simply set the background color on ChatBubbleSpanLabelOwn and ChatBubbleSpanLabelOther.

Styles added to css/theme.css to change the chat bubble colors.
/* Set the color of the "Other" users' chat bubbles to red */
ChatBubbleSpanLabelOther {
    background-color: red;
}

/* Set text color on "Other" users' chat bubbles. */
ChatBubbleTextOther {
    color: white;
}

/* Set the color of the app user's chat bubbles to green */
ChatBubbleSpanLabelOwn {
    background-color: green;
}

/* Set color of app user's chat bubble text to white. */
ChatBubbleTextOwn {
    color: white;
}

And the result:

Image 160420 033304.488
Figure 1. Other users' chat bubble is a hideous red color as specified in CSS.
Image 160420 033341.052
Figure 2. The app user’s chat bubble color is green as specified in CSS.

Using a 9-Piece Border

For more complex chat bubble looks you may want to use a 9-piece border, as this will allow you to design any bubble you like in Photoshop, or find an existing chat bubble graphic online. For this example, we’re going to use the following images:

Image 160420 033612.343
Figure 3. chat-bubble-left.png
Image 160420 033700.794
Figure 4. chat-bubble-right.png

Copy these images into your css/images directory, and then add the following snippet into your project’s css/theme.css file:

css/theme.css File styles to use 9-piece borders for bubbles.
ChatBubbleSpanLabelOther {
    border-image: url(images/chat-bubble-left.png); (1)
    cn1-source-dpi: 480; (2)
    border-image-slice: 5% 1% 94% 5%; (3)
    padding-left:1mm;
    padding-right:0;
}

ChatBubbleTextOther {
    margin: 2mm;
    color: black;
}
ChatBubbleSpanLabelOwn {

    border-image: url(images/chat-bubble-right.png);
    cn1-source-dpi: 480;
    border-image-slice: 5% 5% 94% 1%;
    padding-right: 1mm;
    padding-left:0;
}

ChatBubbleTextOwn {
    color: black;
    margin:2mm;
}
  1. The border-image property specifies the image to use as the background-image.

  2. The cn1-source-dpi directive allows you to specify the "source" DPI of the image. The CSS compiler scales the image to various sizes for use on devices with different densities. The most commonly used values here are 160, 320, and 480. You can experiment with values here. A large value will result in the image appearing smaller in the app.

  3. The border-image-slice specifies how the image should be "sliced" to make the 9-piece border. These values were arrived at using trial and error. When using 4 values, they are interpreted as <top> <right> <bottom> <left>. E.g the first value specifies the distance from the top edge to slice the image as a percentage of the image height. See the Codename One manual’s discussion on 9-piece borders for more details on this directive.

The result:

Image 160420 035423.086
Figure 5. The chat bubbles after applying the styles for the 9-piece image border,

2. Disabling Swipe Left to Reveal Time Posted

Problem

Image 290420 042743.374
Figure 6. Screenshot showing the times of the messages shown along the right. These are revealed while the user has swiped to the left.

By default the ChatRoomView allows users to swipe a chat bubble to the left to see the time that is was posted. In some cases this swiping behaviour may interfere with other gestures in your app, so you may wish to disable the behaviour.

Solution

Use the ChatBubbleView.USE_OVERFLOW_CONTAINER view property in your view node to disable this behaviour as follows:

import static com.codename1.rad.ui.UI.param;

...


Entity viewModel = ....;
Form f = ...;
ViewNode viewNode = new ViewNode(
    param(ChatBubbleView.USE_OVERFLOW_CONTAINER, false),

    // .. Other attributes in the view node...
);

ChatRoomView chatView = new ChatRoomView(viewModel, viewNode, f);
...

See the complete example code here.

Discussion

The ViewProperty is used throughout CodeRAD to add customization of components via the view node hierarchy. Generally components will declare the view properties that they support in their javadocs, as public static final properties. That is how the USE_OVERFLOW_CONTAINER property is defined in the ChatBubbleView component. This particular view property allows us to "switch" off the swipe left behaviour in the chat room.

Further Reading

3. Using An Entity for The "Posted By" Property of Chat Message

Problem

You want to use an Entity for the ChatMessage.creator property in your chat message view model, rather than just incorporating "icon" and "posted by" string properties directly.

Solution

Note

The Getting Started Tutorial uses the reference class ChatBubbleView.ViewModel as the view model for its chat bubbles. This recipe assumes that you’re already using a custom entity class for your Chat message view model. This class may look something like:

A sample view model for a ChatMessage.
package com.codename1.cn1chat;

import com.codename1.rad.models.Entity;
import com.codename1.rad.models.EntityType;
import com.codename1.rad.schemas.ChatMessage;

/**
 * View model for a chat message.
 * @author shannah
 */
public class ChatMessageModel extends Entity {
    public static final EntityType TYPE = new EntityType(){{
        string(ChatMessage.text);
        date(ChatMessage.datePublished);
        string(ChatMessage.icon); (1)
        string(ChatMessage.creator); (2)
        Boolean(ChatMessage.isOwnMessage);
        string(ChatMessage.attachmentPlaceholderImage);
    }};
    {
        setEntityType(TYPE);

    }

}
  1. The avatar for the chat message is stored in the ChatMessage.icon tag.

  2. The name of the user who posted the message is stored in the ChatMessage.creator tag.

Tip
We use tags from the ChatMessage schema for most of the fields in our view model. This schema is part of the CodeRAD class library. This schema isn’t listed on schema.org, it was created to encapsulate chat application messages directly, but it extends the Comment schema, which is a standard schema.

First, let’s change this view model to use an entity for the creator instead of a string. I.e., change:

string(ChatMessage.icon);
string(ChatMessage.creator);

to

entity(ChatAccount.class, ChatMessage.creator);

This says that the "creator" property will be an Entity of type ChatAccount. ChatAccount will be another customer view model class that we’ll create next which encapsulates an account in your chat app.

package com.codename1.cn1chat;
import com.codename1.rad.models.Entity;
import com.codename1.rad.models.EntityType;
import static com.codename1.rad.models.EntityType.tags;
import com.codename1.rad.models.StringProperty;
import com.codename1.rad.schemas.Person;
import com.codename1.rad.schemas.Thing;

/**
 * View model for an account profile.
 * @author shannah
 */
public class ChatAccount extends Entity {

    private static final EntityType TYPE = new EntityType() {{
        name = string(Thing.name); (1)
        thumbnailUrl = string(Thing.thumbnailUrl); (2)
        phone = string(Person.telephone); (3)
    }};
    {
        setEntityType(TYPE);
    }

    public ChatAccount(String nm, String thumb, String phoneNum) { (4)
        set(name, nm);
        set(thumbnailUrl, thumb);
        set(phone, phoneNum);
    }

}
  1. We use the Thing.name tag for the field that stores the user name.

  2. We use the Thing.thumbnailUrl tag for the field that stores the avatar.

  3. We add a telephone field here as an example of one of the extra metadata fields that you may want to use.

Tip
For the ChatAccount entity, we use mostly tags from the Person schema. Though we are referencing Thing.name and Thing.thumbnailUrl, these could have equivalently been referenced as Person.name and Person.thumbnailUrl since Thing is a super-interface of Person and all fields are inherited.

After this adjustment, you’ll need to make a few changes to your app in places where you interact with the view model. In the Adding Text Messages from other users section of the Getting Started Tutorial, we created demo messages using the following method:

// Create a single demo message
private Entity createDemoMessage(String text,
        Date datePosted,
        String participant,
        String iconUrl) {
    ChatBubbleView.ViewModel msg = new ChatBubbleView.ViewModel();
    msg.messageText(text)
            .date(datePosted)
            .iconUrl(iconUrl)
            .isOwn(participant == null);
    if (participant != null) {
        msg.postedBy(participant);
    }
    return msg;

}

Let’s change this method to accept a ChatAccount object instead of the name and icon Url of the participant. At the same time, we’ll update it to use our custom view model for the demo message.

private Entity createDemoMessage(String text, Date datePosted, ChatAccount participant) {
    ChatMessageModel msg = new ChatMessageModel();
    msg.set(ChatMessage.text, text);
    msg.set(ChatMessage.datePublished, datePosted);
    msg.set(ChatMessage.creator, participant);
    msg.set(ChatMessage.isOwnMessage, participant == null);

    return msg;

}

The following is the method that creates the view model for my demo chat room. It demostrates how our view models are used:

private Entity createViewModel() {
    String georgeThumb = "https://weblite.ca/cn1tests/radchat/george.jpg";
    String kramerThumb = "https://weblite.ca/cn1tests/radchat/kramer.jpg";
    ChatAccount george = new ChatAccount("George", georgeThumb, "712-555-1234");
    ChatAccount kramer = new ChatAccount("Kramer", kramerThumb, null);

    ChatRoomView.ViewModel room = new ChatRoomView.ViewModel();
    long SECOND = 1000l;
    long MINUTE = SECOND * 60;
    long HOUR = MINUTE * 60;
    long DAY = HOUR * 24;
    long t = System.currentTimeMillis() - 2 * DAY;



    room.addMessages(createDemoMessage("Why couldn't you have made me an architect? You know I always wanted to pretend that I was an architect. "
            + "Well I'm supposed to see her tomorrow, I'm gonna tell her what's goin on. Maybe she likes me for me.",
            new Date(t), george));
    t += HOUR;
    room.addMessages(createDemoMessage("Hey", new Date(t),kramer));
    t += MINUTE;
    room.addMessages(createDemoMessage("Hey", new Date(t), null));

    Entity vm = createDemoMessage("Hey ya want these? I don't want em!", new Date(t), kramer);
    vm.setText(ChatMessage.attachmentPlaceholderImage, "https://weblite.ca/cn1tests/radchat/golf-clubs.jpg");
    room.addMessages(vm);

    room.addParticipants(george, kramer);

    return room;
}