SlideShare a Scribd company logo
Creating a Facebook Clone - Part XV
The one last form we’ll work on in the mockup stage is the “New Post” Form
© Codename One 2017 all rights reserved
Right now I'll only support simple variations of the new post. I'll deal with image & video posting later. We will discuss some builtin styles and use HTML to display
formatted posts. This could allow for logic that implements things such as hashtags etc. in a future implementation.
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
public NewPostForm() {
super("Create Post", new BorderLayout());
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> {});
User me = ServerAPI.me();
Container userSettings = BorderLayout.west(
new Label(me.getAvatar(6.5f), "HalfPaddedContainer"));
Button friends = new Button("Friends", "FriendCombo");
FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE);
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
NewPostForm
Unlike the tabs we had until now the new post is a separate Form
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
public NewPostForm() {
super("Create Post", new BorderLayout());
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> {});
User me = ServerAPI.me();
Container userSettings = BorderLayout.west(
new Label(me.getAvatar(6.5f), "HalfPaddedContainer"));
Button friends = new Button("Friends", "FriendCombo");
FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE);
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
NewPostForm
The new post form includes styles that can be applied to the editing such as colors, background images etc.
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
public NewPostForm() {
super("Create Post", new BorderLayout());
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> {});
User me = ServerAPI.me();
Container userSettings = BorderLayout.west(
new Label(me.getAvatar(6.5f), "HalfPaddedContainer"));
Button friends = new Button("Friends", "FriendCombo");
FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE);
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
NewPostForm
The Form itself uses a BorderLayout to position a title area on the top and the rest of the UI over the entire screen
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
public NewPostForm() {
super("Create Post", new BorderLayout());
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> {});
User me = ServerAPI.me();
Container userSettings = BorderLayout.west(
new Label(me.getAvatar(6.5f), "HalfPaddedContainer"));
Button friends = new Button("Friends", "FriendCombo");
FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE);
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
NewPostForm
We save the current form before showing so we can go back to it
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
public NewPostForm() {
super("Create Post", new BorderLayout());
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> {});
User me = ServerAPI.me();
Container userSettings = BorderLayout.west(
new Label(me.getAvatar(6.5f), "HalfPaddedContainer"));
Button friends = new Button("Friends", "FriendCombo");
FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE);
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
NewPostForm
The avatar of the user goes on the left side of the title area followed by a button that should let us pick the right visibility mode for the post
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> {});
User me = ServerAPI.me();
Container userSettings = BorderLayout.west(
new Label(me.getAvatar(6.5f), "HalfPaddedContainer"));
Button friends = new Button("Friends", "FriendCombo");
FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE);
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
add(NORTH, userSettings);
TextArea post = new TextArea(3, 80);
post.setUIID("Label");
post.setGrowByContent(false);
Container postStyles = createPostStyles(post);
add(CENTER, LayeredLayout.encloseIn(
BorderLayout.north(post), BorderLayout.south(postStyles)));
setEditOnShow(post);
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
NewPostForm
The text of the post is just a standard TextArea with 3 rows and 80 columns. These are just hints for the preferred size of the component
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> {});
User me = ServerAPI.me();
Container userSettings = BorderLayout.west(
new Label(me.getAvatar(6.5f), "HalfPaddedContainer"));
Button friends = new Button("Friends", "FriendCombo");
FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE);
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
add(NORTH, userSettings);
TextArea post = new TextArea(3, 80);
post.setUIID("Label");
post.setGrowByContent(false);
Container postStyles = createPostStyles(post);
add(CENTER, LayeredLayout.encloseIn(
BorderLayout.north(post), BorderLayout.south(postStyles)));
setEditOnShow(post);
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
NewPostForm
If we input more than 3 rows the UI shouldn't grow, it might go on top of the the post styles container and it would be hard to differentiate a tap there from a text edit
gesture
BorderLayout.north(post), BorderLayout.south(postStyles)));
setEditOnShow(post);
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
int size = convertToPixels(8);
ButtonGroup bg = new ButtonGroup();
for(String s : POST_STYLES) {
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
NewPostForm
This method creates the bar at the bottom of the screen, 

When we click an entry in the bar the look changes and the post gets a new style
BorderLayout.north(post), BorderLayout.south(postStyles)));
setEditOnShow(post);
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
int size = convertToPixels(8);
ButtonGroup bg = new ButtonGroup();
for(String s : POST_STYLES) {
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
NewPostForm
The bar on the bottom of the form is an X axis box layout that's scrollable on the X axis
BorderLayout.north(post), BorderLayout.south(postStyles)));
setEditOnShow(post);
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
int size = convertToPixels(8);
ButtonGroup bg = new ButtonGroup();
for(String s : POST_STYLES) {
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
NewPostForm
Every icon is 8 millimeter in size
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
int size = convertToPixels(8);
ButtonGroup bg = new ButtonGroup();
for(String s : POST_STYLES) {
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
NewPostForm
We loop over the style types, the first style is "Label" which means an unstyled regular post
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
int size = convertToPixels(8);
ButtonGroup bg = new ButtonGroup();
for(String s : POST_STYLES) {
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
NewPostForm
We create a radio toggle button for every style and set the style to the button
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
int size = convertToPixels(8);
ButtonGroup bg = new ButtonGroup();
for(String s : POST_STYLES) {
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
NewPostForm
For the round corners we use the RoundRectBorder class and apply it manually as the style is designed for the entire entry
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
postStyles.setScrollableX(true);
int size = convertToPixels(8);
ButtonGroup bg = new ButtonGroup();
for(String s : POST_STYLES) {
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
NewPostForm
The first entry is a special case because text fields are sometimes transparent and so are labels
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
postStyleButton.setPreferredSize(new Dimension(size, size));
postStyles.add(postStyleButton);
}
return postStyles;
}
NewPostForm
This implements the selected line border around an entry notice strokeColor can be black when surrounding the white label entry
Button postStyleButton = RadioButton.createToggle("", bg);
postStyleButton.setShowEvenIfBlank(true);
postStyleButton.setUIID(s);
Style stl = postStyleButton.getAllStyles();
stl.setBorder(RoundRectBorder.create());
stl.setPadding(3, 3, 3, 3);
stl.setMarginUnit(Style.UNIT_TYPE_DIPS);
stl.setMargin(1, 1, 1, 1);
int strokeColor = 0xffffff;
if(s.equals("Label")) {
stl.setBgTransparency(255);
stl.setBgColor(0xffffff);
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
postStyleButton.setPreferredSize(new Dimension(size, size));
postStyles.add(postStyleButton);
}
return postStyles;
}
NewPostForm
When the user clicks one of these radio buttons we invoke the changeStyle method
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
postStyleButton.setPreferredSize(new Dimension(size, size));
postStyles.add(postStyleButton);
}
return postStyles;
}
private void changeStyle(TextArea post, String s) {
if(s.equals("Label")) {
post.setUIID(s);
post.getParent().setUIID("Container");
} else {
post.setUIID("PostStyleText");
post.getParent().setUIID(s);
}
revalidate();
}
}
NewPostForm
This brings us directly to the changeStyle method
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
postStyleButton.setPreferredSize(new Dimension(size, size));
postStyles.add(postStyleButton);
}
return postStyles;
}
private void changeStyle(TextArea post, String s) {
if(s.equals("Label")) {
post.setUIID(s);
post.getParent().setUIID("Container");
} else {
post.setUIID("PostStyleText");
post.getParent().setUIID(s);
}
revalidate();
}
}
NewPostForm
We need a special case for the first entry again as the behavior is slightly different
strokeColor = 0;
}
postStyleButton.getPressedStyle().setBorder(RoundRectBorder.
create().strokeColor(strokeColor).
strokeOpacity(255).
stroke(0.5f, true));
postStyleButton.addActionListener(e -> changeStyle(post, s));
postStyleButton.setPreferredSize(new Dimension(size, size));
postStyles.add(postStyleButton);
}
return postStyles;
}
private void changeStyle(TextArea post, String s) {
if(s.equals("Label")) {
post.setUIID(s);
post.getParent().setUIID("Container");
} else {
post.setUIID("PostStyleText");
post.getParent().setUIID(s);
}
revalidate();
}
}
NewPostForm
Separate UIID's are needed for the text area and the foreground
}
if(p.comments.size() > 0) {
stats.add(EAST, new Label(p.comments.size() + " comments",
"SmallLabel"));
}
return stats;
}
private Container createPostBar() {
Button avatar = new Button(ServerAPI.me().getAvatar(6.5f), "Label");
Button writePost = new Button("What's on your mind?",
"NewPostButton");
Button gallery = new Button("Photo", "GalleryButton");
FontImage.setMaterialIcon(gallery,
FontImage.MATERIAL_PHOTO_LIBRARY, 2.9f);
gallery.setTextPosition(BOTTOM);
Container c = BorderLayout.
centerEastWest(writePost, gallery, avatar);
c.setUIID("HalfPaddedContainer");
writePost.addActionListener(e -> new NewPostForm().show());
return c;
}
}
NewsfeedContainer
Before we go into the CSS we need one more thing to get this working. We need the following line in the NewsfeedContainer class in the createPostBar() method.
FriendCombo {
padding: 2mm;
margin: 1mm;
border-radius: 1mm;
border-width: 1px;
border-color: gray;
background: transparent;
color: gray;
font-family: "native:MainLight";
font-size: 2.6mm;
}
PostStyleBase {
background-color: black;
color: white;
padding: 3mm;
text-align: center;
font-family: "native:MainRegular";
font-size: 4.5mm;
}
PostStyleHearts {
cn1-derive: PostStyleBase;
background-image: url(images/hearts.jpg);
theme.css
There is quite a bit of CSS listed here, lets start with the simple stuff. The FriendCombo. This is the gray round rect border that's applied to the visibility button. This
button determines if something is seen only by friends or is public
FriendCombo {
padding: 2mm;
margin: 1mm;
border-radius: 1mm;
border-width: 1px;
border-color: gray;
background: transparent;
color: gray;
font-family: "native:MainLight";
font-size: 2.6mm;
}
PostStyleBase {
background-color: black;
color: white;
padding: 3mm;
text-align: center;
font-family: "native:MainRegular";
font-size: 4.5mm;
}
PostStyleHearts {
cn1-derive: PostStyleBase;
background-image: url(images/hearts.jpg);
theme.css
This is the base UIID for every one of the UIID's listed in the array it isn't mentioned in the code but it's used in the CSS itself
color: white;
padding: 3mm;
text-align: center;
font-family: "native:MainRegular";
font-size: 4.5mm;
}
PostStyleHearts {
cn1-derive: PostStyleBase;
background-image: url(images/hearts.jpg);
cn1-source-dpi: 0;
cn1-background-type: cn1-image-scaled-fill;
}
PostStyleHands {
cn1-derive: PostStyleBase;
background-image: url(images/hands.jpg);
cn1-source-dpi: 0;
cn1-background-type: cn1-image-scaled-fit;
background: #243761;
}
PostStyleBlack {
cn1-derive: PostStyleBase;
}
PostStyleRed {
cn1-derive: PostStyleBase;
background: red;
}
theme.css
Next we have the CSS definitions of the text styles. For this code we'll need hearts.jpg & hands.jpg that represent two of the designs.

Notice that all the styles here derive from PostStyleBase. I fill the hearts pattern into place even though it might make sense to tile it in some cases.
background-image: url(images/hearts.jpg);
cn1-source-dpi: 0;
cn1-background-type: cn1-image-scaled-fill;
}
PostStyleHands {
cn1-derive: PostStyleBase;
background-image: url(images/hands.jpg);
cn1-source-dpi: 0;
cn1-background-type: cn1-image-scaled-fit;
background: #243761;
}
PostStyleBlack {
cn1-derive: PostStyleBase;
}
PostStyleRed {
cn1-derive: PostStyleBase;
background: red;
}
PostStylePurple {
cn1-derive: PostStyleBase;
background: #c600ff;
}
PostStyleText {
background: transparent;
color: white;
padding: 1.5mm;
theme.css
I scale to fit the hands entry, I'm not sure if it's the best way as even in the native app the hands disappear in some cases
cn1-derive: PostStyleBase;
background-image: url(images/hands.jpg);
cn1-source-dpi: 0;
cn1-background-type: cn1-image-scaled-fit;
background: #243761;
}
PostStyleBlack {
cn1-derive: PostStyleBase;
}
PostStyleRed {
cn1-derive: PostStyleBase;
background: red;
}
PostStylePurple {
cn1-derive: PostStyleBase;
background: #c600ff;
}
PostStyleText {
background: transparent;
color: white;
padding: 1.5mm;
text-align: center;
font-family: "native:MainRegular";
font-size: 3.5mm;
}
theme.css
The rest of the styles are pretty trivial and should be easy to understand
cn1-derive: PostStyleBase;
background-image: url(images/hands.jpg);
cn1-source-dpi: 0;
cn1-background-type: cn1-image-scaled-fit;
background: #243761;
}
PostStyleBlack {
cn1-derive: PostStyleBase;
}
PostStyleRed {
cn1-derive: PostStyleBase;
background: red;
}
PostStylePurple {
cn1-derive: PostStyleBase;
background: #c600ff;
}
PostStyleText {
background: transparent;
color: white;
padding: 1.5mm;
text-align: center;
font-family: "native:MainRegular";
font-size: 3.5mm;
}
theme.css
This is the style of the foreground text when another style is applied to the background. With that we are done. You should have a working mockup with a signup wizard
and the core functionality we will work on.

More Related Content

PDF
Creating a Facebook Clone - Part XVI.pdf
PDF
Creating a Facebook Clone - Part XLI - Transcript.pdf
PDF
Creating a Facebook Clone - Part XLI.pdf
PDF
Creating a Facebook Clone - Part XXIX - Transcript.pdf
PDF
Creating a Facebook Clone - Part XIII - Transcript.pdf
PDF
Creating a Facebook Clone - Part XIII.pdf
PDF
Creating a Facebook Clone - Part XXXV - Transcript.pdf
PDF
Creating a Facebook Clone - Part XXVIII - Transcript.pdf
Creating a Facebook Clone - Part XVI.pdf
Creating a Facebook Clone - Part XLI - Transcript.pdf
Creating a Facebook Clone - Part XLI.pdf
Creating a Facebook Clone - Part XXIX - Transcript.pdf
Creating a Facebook Clone - Part XIII - Transcript.pdf
Creating a Facebook Clone - Part XIII.pdf
Creating a Facebook Clone - Part XXXV - Transcript.pdf
Creating a Facebook Clone - Part XXVIII - Transcript.pdf

Similar to Creating a Facebook Clone - Part XVI - Transcript.pdf (20)

PDF
Creating a Facebook Clone - Part XXIX.pdf
PDF
Creating a Facebook Clone - Part XXX - Transcript.pdf
PDF
Creating a Facebook Clone - Part XXX.pdf
PDF
How do I - Create a List of Items - Transcript.pdf
PDF
Creating a Facebook Clone - Part IV.pdf
PDF
Creating a Whatsapp Clone - Part V - Transcript.pdf
PDF
Creating a Facebook Clone - Part XLII.pdf
PDF
Creating a Facebook Clone - Part XLII - Transcript.pdf
PDF
Creating a Facebook Clone - Part XXXV.pdf
PDF
Creating a Facebook Clone - Part XLIII.pdf
PDF
Creating a Facebook Clone - Part XLIII - Transcript.pdf
PDF
Creating a Facebook Clone - Part XXXVI.pdf
PDF
Creating a Facebook Clone - Part XXXVI - Transcript.pdf
PDF
Creating an Uber Clone - Part XXXX - Transcript.pdf
PDF
Creating a Facebook Clone - Part XII.pdf
PDF
Creating a Facebook Clone - Part IV - Transcript.pdf
PDF
Creating a Whatsapp Clone - Part V.pdf
PDF
Creating a Whatsapp Clone - Part X.pdf
PDF
create-netflix-clone-06-client-ui_transcript.pdf
PDF
Creating a Whatsapp Clone - Part X - Transcript.pdf
Creating a Facebook Clone - Part XXIX.pdf
Creating a Facebook Clone - Part XXX - Transcript.pdf
Creating a Facebook Clone - Part XXX.pdf
How do I - Create a List of Items - Transcript.pdf
Creating a Facebook Clone - Part IV.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Facebook Clone - Part XLII.pdf
Creating a Facebook Clone - Part XLII - Transcript.pdf
Creating a Facebook Clone - Part XXXV.pdf
Creating a Facebook Clone - Part XLIII.pdf
Creating a Facebook Clone - Part XLIII - Transcript.pdf
Creating a Facebook Clone - Part XXXVI.pdf
Creating a Facebook Clone - Part XXXVI - Transcript.pdf
Creating an Uber Clone - Part XXXX - Transcript.pdf
Creating a Facebook Clone - Part XII.pdf
Creating a Facebook Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part V.pdf
Creating a Whatsapp Clone - Part X.pdf
create-netflix-clone-06-client-ui_transcript.pdf
Creating a Whatsapp Clone - Part X - Transcript.pdf

More from ShaiAlmog1 (20)

PDF
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
PDF
create-netflix-clone-06-client-ui.pdf
PDF
create-netflix-clone-01-introduction_transcript.pdf
PDF
create-netflix-clone-02-server_transcript.pdf
PDF
create-netflix-clone-04-server-continued_transcript.pdf
PDF
create-netflix-clone-01-introduction.pdf
PDF
create-netflix-clone-03-server.pdf
PDF
create-netflix-clone-04-server-continued.pdf
PDF
create-netflix-clone-05-client-model_transcript.pdf
PDF
create-netflix-clone-03-server_transcript.pdf
PDF
create-netflix-clone-02-server.pdf
PDF
create-netflix-clone-05-client-model.pdf
PDF
Creating a Whatsapp Clone - Part II.pdf
PDF
Creating a Whatsapp Clone - Part IX - Transcript.pdf
PDF
Creating a Whatsapp Clone - Part II - Transcript.pdf
PDF
Creating a Whatsapp Clone - Part IV - Transcript.pdf
PDF
Creating a Whatsapp Clone - Part IV.pdf
PDF
Creating a Whatsapp Clone - Part I - Transcript.pdf
PDF
Creating a Whatsapp Clone - Part IX.pdf
PDF
Creating a Whatsapp Clone - Part VI.pdf
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-01-introduction.pdf
create-netflix-clone-03-server.pdf
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-02-server.pdf
create-netflix-clone-05-client-model.pdf
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part VI.pdf

Recently uploaded (20)

PPT
Teaching material agriculture food technology
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Electronic commerce courselecture one. Pdf
PPTX
sap open course for s4hana steps from ECC to s4
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
KodekX | Application Modernization Development
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Spectroscopy.pptx food analysis technology
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
cuic standard and advanced reporting.pdf
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Empathic Computing: Creating Shared Understanding
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
Teaching material agriculture food technology
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
“AI and Expert System Decision Support & Business Intelligence Systems”
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Electronic commerce courselecture one. Pdf
sap open course for s4hana steps from ECC to s4
Digital-Transformation-Roadmap-for-Companies.pptx
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
KodekX | Application Modernization Development
Chapter 3 Spatial Domain Image Processing.pdf
Spectroscopy.pptx food analysis technology
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Agricultural_Statistics_at_a_Glance_2022_0.pdf
cuic standard and advanced reporting.pdf
Review of recent advances in non-invasive hemoglobin estimation
Network Security Unit 5.pdf for BCA BBA.
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Empathic Computing: Creating Shared Understanding
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
The Rise and Fall of 3GPP – Time for a Sabbatical?

Creating a Facebook Clone - Part XVI - Transcript.pdf

  • 1. Creating a Facebook Clone - Part XV The one last form we’ll work on in the mockup stage is the “New Post” Form
  • 2. © Codename One 2017 all rights reserved Right now I'll only support simple variations of the new post. I'll deal with image & video posting later. We will discuss some builtin styles and use HTML to display formatted posts. This could allow for logic that implements things such as hashtags etc. in a future implementation.
  • 3. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; public NewPostForm() { super("Create Post", new BorderLayout()); Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> {}); User me = ServerAPI.me(); Container userSettings = BorderLayout.west( new Label(me.getAvatar(6.5f), "HalfPaddedContainer")); Button friends = new Button("Friends", "FriendCombo"); FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE); userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); NewPostForm Unlike the tabs we had until now the new post is a separate Form
  • 4. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; public NewPostForm() { super("Create Post", new BorderLayout()); Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> {}); User me = ServerAPI.me(); Container userSettings = BorderLayout.west( new Label(me.getAvatar(6.5f), "HalfPaddedContainer")); Button friends = new Button("Friends", "FriendCombo"); FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE); userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); NewPostForm The new post form includes styles that can be applied to the editing such as colors, background images etc.
  • 5. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; public NewPostForm() { super("Create Post", new BorderLayout()); Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> {}); User me = ServerAPI.me(); Container userSettings = BorderLayout.west( new Label(me.getAvatar(6.5f), "HalfPaddedContainer")); Button friends = new Button("Friends", "FriendCombo"); FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE); userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); NewPostForm The Form itself uses a BorderLayout to position a title area on the top and the rest of the UI over the entire screen
  • 6. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; public NewPostForm() { super("Create Post", new BorderLayout()); Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> {}); User me = ServerAPI.me(); Container userSettings = BorderLayout.west( new Label(me.getAvatar(6.5f), "HalfPaddedContainer")); Button friends = new Button("Friends", "FriendCombo"); FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE); userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); NewPostForm We save the current form before showing so we can go back to it
  • 7. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; public NewPostForm() { super("Create Post", new BorderLayout()); Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> {}); User me = ServerAPI.me(); Container userSettings = BorderLayout.west( new Label(me.getAvatar(6.5f), "HalfPaddedContainer")); Button friends = new Button("Friends", "FriendCombo"); FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE); userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); NewPostForm The avatar of the user goes on the left side of the title area followed by a button that should let us pick the right visibility mode for the post
  • 8. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> {}); User me = ServerAPI.me(); Container userSettings = BorderLayout.west( new Label(me.getAvatar(6.5f), "HalfPaddedContainer")); Button friends = new Button("Friends", "FriendCombo"); FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE); userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); add(NORTH, userSettings); TextArea post = new TextArea(3, 80); post.setUIID("Label"); post.setGrowByContent(false); Container postStyles = createPostStyles(post); add(CENTER, LayeredLayout.encloseIn( BorderLayout.north(post), BorderLayout.south(postStyles))); setEditOnShow(post); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); NewPostForm The text of the post is just a standard TextArea with 3 rows and 80 columns. These are just hints for the preferred size of the component
  • 9. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> {}); User me = ServerAPI.me(); Container userSettings = BorderLayout.west( new Label(me.getAvatar(6.5f), "HalfPaddedContainer")); Button friends = new Button("Friends", "FriendCombo"); FontImage.setMaterialIcon(friends, FontImage.MATERIAL_PEOPLE); userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); add(NORTH, userSettings); TextArea post = new TextArea(3, 80); post.setUIID("Label"); post.setGrowByContent(false); Container postStyles = createPostStyles(post); add(CENTER, LayeredLayout.encloseIn( BorderLayout.north(post), BorderLayout.south(postStyles))); setEditOnShow(post); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); NewPostForm If we input more than 3 rows the UI shouldn't grow, it might go on top of the the post styles container and it would be hard to differentiate a tap there from a text edit gesture
  • 10. BorderLayout.north(post), BorderLayout.south(postStyles))); setEditOnShow(post); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); int size = convertToPixels(8); ButtonGroup bg = new ButtonGroup(); for(String s : POST_STYLES) { Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). NewPostForm This method creates the bar at the bottom of the screen, When we click an entry in the bar the look changes and the post gets a new style
  • 11. BorderLayout.north(post), BorderLayout.south(postStyles))); setEditOnShow(post); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); int size = convertToPixels(8); ButtonGroup bg = new ButtonGroup(); for(String s : POST_STYLES) { Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). NewPostForm The bar on the bottom of the form is an X axis box layout that's scrollable on the X axis
  • 12. BorderLayout.north(post), BorderLayout.south(postStyles))); setEditOnShow(post); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); int size = convertToPixels(8); ButtonGroup bg = new ButtonGroup(); for(String s : POST_STYLES) { Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). NewPostForm Every icon is 8 millimeter in size
  • 13. private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); int size = convertToPixels(8); ButtonGroup bg = new ButtonGroup(); for(String s : POST_STYLES) { Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); NewPostForm We loop over the style types, the first style is "Label" which means an unstyled regular post
  • 14. private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); int size = convertToPixels(8); ButtonGroup bg = new ButtonGroup(); for(String s : POST_STYLES) { Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); NewPostForm We create a radio toggle button for every style and set the style to the button
  • 15. private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); int size = convertToPixels(8); ButtonGroup bg = new ButtonGroup(); for(String s : POST_STYLES) { Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); NewPostForm For the round corners we use the RoundRectBorder class and apply it manually as the style is designed for the entire entry
  • 16. private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); postStyles.setScrollableX(true); int size = convertToPixels(8); ButtonGroup bg = new ButtonGroup(); for(String s : POST_STYLES) { Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); NewPostForm The first entry is a special case because text fields are sometimes transparent and so are labels
  • 17. Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); postStyleButton.setPreferredSize(new Dimension(size, size)); postStyles.add(postStyleButton); } return postStyles; } NewPostForm This implements the selected line border around an entry notice strokeColor can be black when surrounding the white label entry
  • 18. Button postStyleButton = RadioButton.createToggle("", bg); postStyleButton.setShowEvenIfBlank(true); postStyleButton.setUIID(s); Style stl = postStyleButton.getAllStyles(); stl.setBorder(RoundRectBorder.create()); stl.setPadding(3, 3, 3, 3); stl.setMarginUnit(Style.UNIT_TYPE_DIPS); stl.setMargin(1, 1, 1, 1); int strokeColor = 0xffffff; if(s.equals("Label")) { stl.setBgTransparency(255); stl.setBgColor(0xffffff); strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); postStyleButton.setPreferredSize(new Dimension(size, size)); postStyles.add(postStyleButton); } return postStyles; } NewPostForm When the user clicks one of these radio buttons we invoke the changeStyle method
  • 19. strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); postStyleButton.setPreferredSize(new Dimension(size, size)); postStyles.add(postStyleButton); } return postStyles; } private void changeStyle(TextArea post, String s) { if(s.equals("Label")) { post.setUIID(s); post.getParent().setUIID("Container"); } else { post.setUIID("PostStyleText"); post.getParent().setUIID(s); } revalidate(); } } NewPostForm This brings us directly to the changeStyle method
  • 20. strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); postStyleButton.setPreferredSize(new Dimension(size, size)); postStyles.add(postStyleButton); } return postStyles; } private void changeStyle(TextArea post, String s) { if(s.equals("Label")) { post.setUIID(s); post.getParent().setUIID("Container"); } else { post.setUIID("PostStyleText"); post.getParent().setUIID(s); } revalidate(); } } NewPostForm We need a special case for the first entry again as the behavior is slightly different
  • 21. strokeColor = 0; } postStyleButton.getPressedStyle().setBorder(RoundRectBorder. create().strokeColor(strokeColor). strokeOpacity(255). stroke(0.5f, true)); postStyleButton.addActionListener(e -> changeStyle(post, s)); postStyleButton.setPreferredSize(new Dimension(size, size)); postStyles.add(postStyleButton); } return postStyles; } private void changeStyle(TextArea post, String s) { if(s.equals("Label")) { post.setUIID(s); post.getParent().setUIID("Container"); } else { post.setUIID("PostStyleText"); post.getParent().setUIID(s); } revalidate(); } } NewPostForm Separate UIID's are needed for the text area and the foreground
  • 22. } if(p.comments.size() > 0) { stats.add(EAST, new Label(p.comments.size() + " comments", "SmallLabel")); } return stats; } private Container createPostBar() { Button avatar = new Button(ServerAPI.me().getAvatar(6.5f), "Label"); Button writePost = new Button("What's on your mind?", "NewPostButton"); Button gallery = new Button("Photo", "GalleryButton"); FontImage.setMaterialIcon(gallery, FontImage.MATERIAL_PHOTO_LIBRARY, 2.9f); gallery.setTextPosition(BOTTOM); Container c = BorderLayout. centerEastWest(writePost, gallery, avatar); c.setUIID("HalfPaddedContainer"); writePost.addActionListener(e -> new NewPostForm().show()); return c; } } NewsfeedContainer Before we go into the CSS we need one more thing to get this working. We need the following line in the NewsfeedContainer class in the createPostBar() method.
  • 23. FriendCombo { padding: 2mm; margin: 1mm; border-radius: 1mm; border-width: 1px; border-color: gray; background: transparent; color: gray; font-family: "native:MainLight"; font-size: 2.6mm; } PostStyleBase { background-color: black; color: white; padding: 3mm; text-align: center; font-family: "native:MainRegular"; font-size: 4.5mm; } PostStyleHearts { cn1-derive: PostStyleBase; background-image: url(images/hearts.jpg); theme.css There is quite a bit of CSS listed here, lets start with the simple stuff. The FriendCombo. This is the gray round rect border that's applied to the visibility button. This button determines if something is seen only by friends or is public
  • 24. FriendCombo { padding: 2mm; margin: 1mm; border-radius: 1mm; border-width: 1px; border-color: gray; background: transparent; color: gray; font-family: "native:MainLight"; font-size: 2.6mm; } PostStyleBase { background-color: black; color: white; padding: 3mm; text-align: center; font-family: "native:MainRegular"; font-size: 4.5mm; } PostStyleHearts { cn1-derive: PostStyleBase; background-image: url(images/hearts.jpg); theme.css This is the base UIID for every one of the UIID's listed in the array it isn't mentioned in the code but it's used in the CSS itself
  • 25. color: white; padding: 3mm; text-align: center; font-family: "native:MainRegular"; font-size: 4.5mm; } PostStyleHearts { cn1-derive: PostStyleBase; background-image: url(images/hearts.jpg); cn1-source-dpi: 0; cn1-background-type: cn1-image-scaled-fill; } PostStyleHands { cn1-derive: PostStyleBase; background-image: url(images/hands.jpg); cn1-source-dpi: 0; cn1-background-type: cn1-image-scaled-fit; background: #243761; } PostStyleBlack { cn1-derive: PostStyleBase; } PostStyleRed { cn1-derive: PostStyleBase; background: red; } theme.css Next we have the CSS definitions of the text styles. For this code we'll need hearts.jpg & hands.jpg that represent two of the designs. Notice that all the styles here derive from PostStyleBase. I fill the hearts pattern into place even though it might make sense to tile it in some cases.
  • 26. background-image: url(images/hearts.jpg); cn1-source-dpi: 0; cn1-background-type: cn1-image-scaled-fill; } PostStyleHands { cn1-derive: PostStyleBase; background-image: url(images/hands.jpg); cn1-source-dpi: 0; cn1-background-type: cn1-image-scaled-fit; background: #243761; } PostStyleBlack { cn1-derive: PostStyleBase; } PostStyleRed { cn1-derive: PostStyleBase; background: red; } PostStylePurple { cn1-derive: PostStyleBase; background: #c600ff; } PostStyleText { background: transparent; color: white; padding: 1.5mm; theme.css I scale to fit the hands entry, I'm not sure if it's the best way as even in the native app the hands disappear in some cases
  • 27. cn1-derive: PostStyleBase; background-image: url(images/hands.jpg); cn1-source-dpi: 0; cn1-background-type: cn1-image-scaled-fit; background: #243761; } PostStyleBlack { cn1-derive: PostStyleBase; } PostStyleRed { cn1-derive: PostStyleBase; background: red; } PostStylePurple { cn1-derive: PostStyleBase; background: #c600ff; } PostStyleText { background: transparent; color: white; padding: 1.5mm; text-align: center; font-family: "native:MainRegular"; font-size: 3.5mm; } theme.css The rest of the styles are pretty trivial and should be easy to understand
  • 28. cn1-derive: PostStyleBase; background-image: url(images/hands.jpg); cn1-source-dpi: 0; cn1-background-type: cn1-image-scaled-fit; background: #243761; } PostStyleBlack { cn1-derive: PostStyleBase; } PostStyleRed { cn1-derive: PostStyleBase; background: red; } PostStylePurple { cn1-derive: PostStyleBase; background: #c600ff; } PostStyleText { background: transparent; color: white; padding: 1.5mm; text-align: center; font-family: "native:MainRegular"; font-size: 3.5mm; } theme.css This is the style of the foreground text when another style is applied to the background. With that we are done. You should have a working mockup with a signup wizard and the core functionality we will work on.