SlideShare a Scribd company logo
1 of 21
Download to read offline
Creating a Facebook Clone - Part XLII
The changes to NewsfeedContainer include the final pieces to post a media object & the ability to view a media post. While I was here I also fixed the code for displaying
a styled post which is something I never implemented in the code itself...
}
return stats;
}
private static 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 -> NewPostForm.createPost().show());
gallery.addActionListener(e -> {
ImagePicker p = new ImagePicker(GALLERY_ALL);
p.pick(
image -> {
NewPostForm.createImagePost(image, p).show();
},
video -> {
NewPostForm.createVideoPost(video, p).show();
});
});
NewsfeedContainer
We'll start at the bottom with createPostBar which is where we reference the new API's to post an image/video file.

This was changed from using the constructor to the new factory method
}
return stats;
}
private static 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 -> NewPostForm.createPost().show());
gallery.addActionListener(e -> {
ImagePicker p = new ImagePicker(GALLERY_ALL);
p.pick(
image -> {
NewPostForm.createImagePost(image, p).show();
},
video -> {
NewPostForm.createVideoPost(video, p).show();
});
});
NewsfeedContainer
The gallery picker launches in an "all" mode which will show both images & videos
private static 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 -> NewPostForm.createPost().show());
gallery.addActionListener(e -> {
ImagePicker p = new ImagePicker(GALLERY_ALL);
p.pick(
image -> {
NewPostForm.createImagePost(image, p).show();
},
video -> {
NewPostForm.createVideoPost(video, p).show();
});
});
return c;
}
}
NewsfeedContainer
We invoke the right type of post based on the user selection. That's a simple change and now we can actually do a media post!

It would actually work but won't show the image in the UI as the code within this class still can't render that. This is simple to fix.
return BoxLayout.encloseY(
titleArea, body, createPostStats(p), buttonBar);
}
private static Image placeholder;
private static Component createMediaComponent(String mime, String id) {
if(mime.startsWith("image")) {
if(placeholder == null) {
placeholder = Image.createImage(getDisplayWidth(),
getDisplayHeight() / 2, 0);
}
ScaleImageButton sb = new ScaleImageButton(
URLImage.createCachedImage(id, ServerAPI.mediaUrl(id),
placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL));
return sb;
} else {
try {
Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id),
true);
MediaPlayer mp = new MediaPlayer(media) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
NewsfeedContainer
First we need a new method that will create a Component to match the given media ID.
return BoxLayout.encloseY(
titleArea, body, createPostStats(p), buttonBar);
}
private static Image placeholder;
private static Component createMediaComponent(String mime, String id) {
if(mime.startsWith("image")) {
if(placeholder == null) {
placeholder = Image.createImage(getDisplayWidth(),
getDisplayHeight() / 2, 0);
}
ScaleImageButton sb = new ScaleImageButton(
URLImage.createCachedImage(id, ServerAPI.mediaUrl(id),
placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL));
return sb;
} else {
try {
Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id),
true);
MediaPlayer mp = new MediaPlayer(media) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
NewsfeedContainer
We'll use this image as a placeholder image for URLImage
return BoxLayout.encloseY(
titleArea, body, createPostStats(p), buttonBar);
}
private static Image placeholder;
private static Component createMediaComponent(String mime, String id) {
if(mime.startsWith("image")) {
if(placeholder == null) {
placeholder = Image.createImage(getDisplayWidth(),
getDisplayHeight() / 2, 0);
}
ScaleImageButton sb = new ScaleImageButton(
URLImage.createCachedImage(id, ServerAPI.mediaUrl(id),
placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL));
return sb;
} else {
try {
Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id),
true);
MediaPlayer mp = new MediaPlayer(media) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
NewsfeedContainer
We initialize it lazily to a size that makes sense for the device
return BoxLayout.encloseY(
titleArea, body, createPostStats(p), buttonBar);
}
private static Image placeholder;
private static Component createMediaComponent(String mime, String id) {
if(mime.startsWith("image")) {
if(placeholder == null) {
placeholder = Image.createImage(getDisplayWidth(),
getDisplayHeight() / 2, 0);
}
ScaleImageButton sb = new ScaleImageButton(
URLImage.createCachedImage(id, ServerAPI.mediaUrl(id),
placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL));
return sb;
} else {
try {
Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id),
true);
MediaPlayer mp = new MediaPlayer(media) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
NewsfeedContainer
Since the image is scaled in the download process there is no need for the calcPreferredSize trick here, we can just use a regular button or label
}
ScaleImageButton sb = new ScaleImageButton(
URLImage.createCachedImage(id, ServerAPI.mediaUrl(id),
placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL));
return sb;
} else {
try {
Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id),
true);
MediaPlayer mp = new MediaPlayer(media) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
mp.setLoop(true);
return mp;
} catch(IOException err) {
Log.e(err);
return new Label("Error loading media");
}
}
}
NewsfeedContainer
A media stream can be played directly from our server URL which is pretty darn cool!
}
ScaleImageButton sb = new ScaleImageButton(
URLImage.createCachedImage(id, ServerAPI.mediaUrl(id),
placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL));
return sb;
} else {
try {
Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id),
true);
MediaPlayer mp = new MediaPlayer(media) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
mp.setLoop(true);
return mp;
} catch(IOException err) {
Log.e(err);
return new Label("Error loading media");
}
}
}
NewsfeedContainer
We need to override preferred size here because the media can be any size. This is a bit over simplified. Proper server media handling will transcode the video to multiple
form factors and deliver the right video type for every device. This saves bandwidth but also makes sure the media is playable avoiding multiple device related issues.
FlowLayout.encloseIn(menu), avatar);
titleArea.setUIID("HalfPaddedContainer");
return titleArea;
}
public static Container createNewsItem(User u, Post p) {
Container titleArea = createNewsTitle(u, p);
Component body;
String style = null;
if(p.styling.get() != null && !p.styling.get().equals("Label")) {
style = p.styling.get();
}
if(p.content.get().indexOf('<') > -1) {
if(style != null) {
body = new RichTextView(p.content.get(), "PostStyleText");
((RichTextView)body).setAlignment(CENTER);
body.setUIID(style);
} else {
body = new RichTextView(p.content.get());
body.setUIID("HalfPaddedContainer");
}
} else {
body = new SpanLabel(p.content.get());
if(style != null) {
((SpanLabel)body).setTextUIID("PostStyleText");
NewsfeedContainer
Now that this is in place we can tie it in to the post rendering logic in createNewsItem
like.setUIID("CleanButton");
Button comment = new Button("Comment", "CleanButton");
Button share = new Button("Share", "CleanButton");
FontImage.setMaterialIcon(like, FontImage.MATERIAL_THUMB_UP);
FontImage.setMaterialIcon(comment,
FontImage.MATERIAL_COMMENT);
FontImage.setMaterialIcon(share, FontImage.MATERIAL_SHARE);
Container buttonBar = GridLayout.encloseIn(3, like, comment, share);
buttonBar.setUIID("HalfPaddedContainer");
like.setSelected(p.likes.contains(u));
like.addActionListener(e -> ServerAPI.like(p));
comment.addActionListener(e -> new CommentsForm(p, null).show());
if(p.attachments.size() > 0) {
String key = p.attachments.keySet().iterator().next();
return BoxLayout.encloseY(titleArea, body,
createMediaComponent(p.attachments.get(key), key),
createPostStats(p), buttonBar);
}
return BoxLayout.encloseY(
titleArea, body, createPostStats(p), buttonBar);
}
NewsfeedContainer
If we have an attachment we add the media component to the bottom of the post.
like.setUIID("CleanButton");
Button comment = new Button("Comment", "CleanButton");
Button share = new Button("Share", "CleanButton");
FontImage.setMaterialIcon(like, FontImage.MATERIAL_THUMB_UP);
FontImage.setMaterialIcon(comment,
FontImage.MATERIAL_COMMENT);
FontImage.setMaterialIcon(share, FontImage.MATERIAL_SHARE);
Container buttonBar = GridLayout.encloseIn(3, like, comment, share);
buttonBar.setUIID("HalfPaddedContainer");
like.setSelected(p.likes.contains(u));
like.addActionListener(e -> ServerAPI.like(p));
comment.addActionListener(e -> new CommentsForm(p, null).show());
if(p.attachments.size() > 0) {
String key = p.attachments.keySet().iterator().next();
return BoxLayout.encloseY(titleArea, body,
createMediaComponent(p.attachments.get(key), key),
createPostStats(p), buttonBar);
}
return BoxLayout.encloseY(
titleArea, body, createPostStats(p), buttonBar);
}
NewsfeedContainer
Otherwise we use the same post code as before. With that media posts will work and show up in your feed!
titleArea.setUIID("HalfPaddedContainer");
return titleArea;
}
public static Container createNewsItem(User u, Post p) {
Container titleArea = createNewsTitle(u, p);
Component body;
String style = null;
if(p.styling.get() != null && !p.styling.get().equals("Label")) {
style = p.styling.get();
}
if(p.content.get().indexOf('<') > -1) {
if(style != null) {
body = new RichTextView(p.content.get(), "PostStyleText");
((RichTextView)body).setAlignment(CENTER);
body.setUIID(style);
} else {
body = new RichTextView(p.content.get());
body.setUIID("HalfPaddedContainer");
}
} else {
body = new SpanLabel(p.content.get());
if(style != null) {
((SpanLabel)body).setTextUIID("PostStyleText");
body.setUIID(style);
NewsfeedContainer
There is however, one additional enhancement I added to the createNewsItem method to support the styled posts which up until now were ignored. I save the result of
the if statement here to make the following code shorter/simpler
Component body;
String style = null;
if(p.styling.get() != null && !p.styling.get().equals("Label")) {
style = p.styling.get();
}
if(p.content.get().indexOf('<') > -1) {
if(style != null) {
body = new RichTextView(p.content.get(), "PostStyleText");
((RichTextView)body).setAlignment(CENTER);
body.setUIID(style);
} else {
body = new RichTextView(p.content.get());
body.setUIID("HalfPaddedContainer");
}
} else {
body = new SpanLabel(p.content.get());
if(style != null) {
((SpanLabel)body).setTextUIID("PostStyleText");
body.setUIID(style);
} else {
body.setUIID("HalfPaddedContainer");
}
}
CheckBox like = CheckBox.createToggle("Like");
like.setUIID("CleanButton");
NewsfeedContainer
RichTextView now accepts a UIID for the content, I'll go into that code soon. The body is given the background style UIID.
Component body;
String style = null;
if(p.styling.get() != null && !p.styling.get().equals("Label")) {
style = p.styling.get();
}
if(p.content.get().indexOf('<') > -1) {
if(style != null) {
body = new RichTextView(p.content.get(), "PostStyleText");
((RichTextView)body).setAlignment(CENTER);
body.setUIID(style);
} else {
body = new RichTextView(p.content.get());
body.setUIID("HalfPaddedContainer");
}
} else {
body = new SpanLabel(p.content.get());
if(style != null) {
((SpanLabel)body).setTextUIID("PostStyleText");
body.setUIID(style);
} else {
body.setUIID("HalfPaddedContainer");
}
}
CheckBox like = CheckBox.createToggle("Like");
like.setUIID("CleanButton");
NewsfeedContainer
The same is true in the `SpanLabel` version of the code...
public class RichTextView extends Container {
private String text;
private float fontSize = 2.6f;
private EventDispatcher listeners = new EventDispatcher();
private Font currentFont;
private int currentColor = 0;
private String currentLink;
private Style lastCmp;
private Font defaultFont;
private Font boldFont;
private Font italicFont;
private int sizeOfSpace;
public RichTextView() {
init(null);
}
public RichTextView(String text, String uiid) {
init(uiid);
setText(text);
}
RichTextView
This leads us directly to the changes in RichTextView.

Because of its nature RichTextView is a bit of a hack without much support for styling. I wanted to give it some generic styling support for the rich posts so this isn't a
huge change but it helps…

First I had to make fontSize non-final as this will change due to styling:
private Font defaultFont;
private Font boldFont;
private Font italicFont;
private int sizeOfSpace;
public RichTextView() {
init(null);
}
public RichTextView(String text, String uiid) {
init(uiid);
setText(text);
}
public RichTextView(String text) {
init(null);
setText(text);
}
private void init(String uiid) {
boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize);
italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize);
if(uiid == null) {
defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT,
fontSize);
} else {
RichTextView
The next step is simply a change to the constructors and init method. Init now accepts an optional UIID which defaults to null.
private Font defaultFont;
private Font boldFont;
private Font italicFont;
private int sizeOfSpace;
public RichTextView() {
init(null);
}
public RichTextView(String text, String uiid) {
init(uiid);
setText(text);
}
public RichTextView(String text) {
init(null);
setText(text);
}
private void init(String uiid) {
boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize);
italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize);
if(uiid == null) {
defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT,
fontSize);
} else {
RichTextView
We set this UIID in this new constructor but leave it as null in the other cases
}
public RichTextView(String text) {
init(null);
setText(text);
}
private void init(String uiid) {
boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize);
italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize);
if(uiid == null) {
defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT,
fontSize);
} else {
Style s = UIManager.getInstance().getComponentStyle(uiid);
defaultFont = s.getFont();
boldFont = boldFont.derive(defaultFont.getHeight(),
Font.STYLE_BOLD);
italicFont = italicFont.derive(defaultFont.getHeight(),
Font.STYLE_ITALIC);
}
sizeOfSpace = defaultFont.charWidth(' ');
currentFont = defaultFont;
}
public void setAlignment(int align) {
RichTextView
If the UIID isn't set everything acts like it did before...
}
public RichTextView(String text) {
init(null);
setText(text);
}
private void init(String uiid) {
boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize);
italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize);
if(uiid == null) {
defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT,
fontSize);
} else {
Style s = UIManager.getInstance().getComponentStyle(uiid);
defaultFont = s.getFont();
boldFont = boldFont.derive(defaultFont.getHeight(),
Font.STYLE_BOLD);
italicFont = italicFont.derive(defaultFont.getHeight(),
Font.STYLE_ITALIC);
}
sizeOfSpace = defaultFont.charWidth(' ');
currentFont = defaultFont;
}
public void setAlignment(int align) {
RichTextView
Otherwise we get the default font from the style then resize the bold/italic fonts to match its size. That's it, we can now style the default font of the rich text view.

More Related Content

Similar to Creating a Facebook Clone - Part XLII - Transcript.pdf

Modify the following source code so that when the mouse is clicked w.pdf
Modify the following source code so that when the mouse is clicked w.pdfModify the following source code so that when the mouse is clicked w.pdf
Modify the following source code so that when the mouse is clicked w.pdf
arorastores
 

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

Creating a Facebook Clone - Part XXIX - Transcript.pdf
Creating a Facebook Clone - Part XXIX - Transcript.pdfCreating a Facebook Clone - Part XXIX - Transcript.pdf
Creating a Facebook Clone - Part XXIX - Transcript.pdf
 
Creating a Facebook Clone - Part XXXVI.pdf
Creating a Facebook Clone - Part XXXVI.pdfCreating a Facebook Clone - Part XXXVI.pdf
Creating a Facebook Clone - Part XXXVI.pdf
 
Creating a Facebook Clone - Part XXVIII.pdf
Creating a Facebook Clone - Part XXVIII.pdfCreating a Facebook Clone - Part XXVIII.pdf
Creating a Facebook Clone - Part XXVIII.pdf
 
Modify the following source code so that when the mouse is clicked w.pdf
Modify the following source code so that when the mouse is clicked w.pdfModify the following source code so that when the mouse is clicked w.pdf
Modify the following source code so that when the mouse is clicked w.pdf
 
Creating a Facebook Clone - Part XII.pdf
Creating a Facebook Clone - Part XII.pdfCreating a Facebook Clone - Part XII.pdf
Creating a Facebook Clone - Part XII.pdf
 
Creating a Facebook Clone - Part XLI - Transcript.pdf
Creating a Facebook Clone - Part XLI - Transcript.pdfCreating a Facebook Clone - Part XLI - Transcript.pdf
Creating a Facebook Clone - Part XLI - Transcript.pdf
 
Creating a Facebook Clone - Part VI - Transcript.pdf
Creating a Facebook Clone - Part VI - Transcript.pdfCreating a Facebook Clone - Part VI - Transcript.pdf
Creating a Facebook Clone - Part VI - Transcript.pdf
 
Creating a Facebook Clone - Part VI.pdf
Creating a Facebook Clone - Part VI.pdfCreating a Facebook Clone - Part VI.pdf
Creating a Facebook Clone - Part VI.pdf
 
Creating a Facebook Clone - Part XVI.pdf
Creating a Facebook Clone - Part XVI.pdfCreating a Facebook Clone - Part XVI.pdf
Creating a Facebook Clone - Part XVI.pdf
 
Creating an Uber Clone - Part XXXX - Transcript.pdf
Creating an Uber Clone - Part XXXX - Transcript.pdfCreating an Uber Clone - Part XXXX - Transcript.pdf
Creating an Uber Clone - Part XXXX - Transcript.pdf
 
Creating a Facebook Clone - Part XV - Transcript.pdf
Creating a Facebook Clone - Part XV - Transcript.pdfCreating a Facebook Clone - Part XV - Transcript.pdf
Creating a Facebook Clone - Part XV - Transcript.pdf
 
Creating a Facebook Clone - Part XL - Transcript.pdf
Creating a Facebook Clone - Part XL - Transcript.pdfCreating a Facebook Clone - Part XL - Transcript.pdf
Creating a Facebook Clone - Part XL - Transcript.pdf
 
Creating a Facebook Clone - Part XVI - Transcript.pdf
Creating a Facebook Clone - Part XVI - Transcript.pdfCreating a Facebook Clone - Part XVI - Transcript.pdf
Creating a Facebook Clone - Part XVI - Transcript.pdf
 
Creating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdfCreating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdf
 
Creating a Facebook Clone - Part X - Transcript.pdf
Creating a Facebook Clone - Part X - Transcript.pdfCreating a Facebook Clone - Part X - Transcript.pdf
Creating a Facebook Clone - Part X - Transcript.pdf
 
Creating a Facebook Clone - Part XLIII.pdf
Creating a Facebook Clone - Part XLIII.pdfCreating a Facebook Clone - Part XLIII.pdf
Creating a Facebook Clone - Part XLIII.pdf
 
Gutenberg sous le capot, modules réutilisables
Gutenberg sous le capot, modules réutilisablesGutenberg sous le capot, modules réutilisables
Gutenberg sous le capot, modules réutilisables
 
Creating a Facebook Clone - Part XV.pdf
Creating a Facebook Clone - Part XV.pdfCreating a Facebook Clone - Part XV.pdf
Creating a Facebook Clone - Part XV.pdf
 
Creating a Facebook Clone - Part XXXIX - Transcript.pdf
Creating a Facebook Clone - Part XXXIX - Transcript.pdfCreating a Facebook Clone - Part XXXIX - Transcript.pdf
Creating a Facebook Clone - Part XXXIX - Transcript.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 

More from ShaiAlmog1

More from ShaiAlmog1 (20)

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

Recently uploaded

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Recently uploaded (20)

Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 

Creating a Facebook Clone - Part XLII - Transcript.pdf

  • 1. Creating a Facebook Clone - Part XLII The changes to NewsfeedContainer include the final pieces to post a media object & the ability to view a media post. While I was here I also fixed the code for displaying a styled post which is something I never implemented in the code itself...
  • 2. } return stats; } private static 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 -> NewPostForm.createPost().show()); gallery.addActionListener(e -> { ImagePicker p = new ImagePicker(GALLERY_ALL); p.pick( image -> { NewPostForm.createImagePost(image, p).show(); }, video -> { NewPostForm.createVideoPost(video, p).show(); }); }); NewsfeedContainer We'll start at the bottom with createPostBar which is where we reference the new API's to post an image/video file. This was changed from using the constructor to the new factory method
  • 3. } return stats; } private static 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 -> NewPostForm.createPost().show()); gallery.addActionListener(e -> { ImagePicker p = new ImagePicker(GALLERY_ALL); p.pick( image -> { NewPostForm.createImagePost(image, p).show(); }, video -> { NewPostForm.createVideoPost(video, p).show(); }); }); NewsfeedContainer The gallery picker launches in an "all" mode which will show both images & videos
  • 4. private static 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 -> NewPostForm.createPost().show()); gallery.addActionListener(e -> { ImagePicker p = new ImagePicker(GALLERY_ALL); p.pick( image -> { NewPostForm.createImagePost(image, p).show(); }, video -> { NewPostForm.createVideoPost(video, p).show(); }); }); return c; } } NewsfeedContainer We invoke the right type of post based on the user selection. That's a simple change and now we can actually do a media post! It would actually work but won't show the image in the UI as the code within this class still can't render that. This is simple to fix.
  • 5. return BoxLayout.encloseY( titleArea, body, createPostStats(p), buttonBar); } private static Image placeholder; private static Component createMediaComponent(String mime, String id) { if(mime.startsWith("image")) { if(placeholder == null) { placeholder = Image.createImage(getDisplayWidth(), getDisplayHeight() / 2, 0); } ScaleImageButton sb = new ScaleImageButton( URLImage.createCachedImage(id, ServerAPI.mediaUrl(id), placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL)); return sb; } else { try { Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id), true); MediaPlayer mp = new MediaPlayer(media) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } NewsfeedContainer First we need a new method that will create a Component to match the given media ID.
  • 6. return BoxLayout.encloseY( titleArea, body, createPostStats(p), buttonBar); } private static Image placeholder; private static Component createMediaComponent(String mime, String id) { if(mime.startsWith("image")) { if(placeholder == null) { placeholder = Image.createImage(getDisplayWidth(), getDisplayHeight() / 2, 0); } ScaleImageButton sb = new ScaleImageButton( URLImage.createCachedImage(id, ServerAPI.mediaUrl(id), placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL)); return sb; } else { try { Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id), true); MediaPlayer mp = new MediaPlayer(media) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } NewsfeedContainer We'll use this image as a placeholder image for URLImage
  • 7. return BoxLayout.encloseY( titleArea, body, createPostStats(p), buttonBar); } private static Image placeholder; private static Component createMediaComponent(String mime, String id) { if(mime.startsWith("image")) { if(placeholder == null) { placeholder = Image.createImage(getDisplayWidth(), getDisplayHeight() / 2, 0); } ScaleImageButton sb = new ScaleImageButton( URLImage.createCachedImage(id, ServerAPI.mediaUrl(id), placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL)); return sb; } else { try { Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id), true); MediaPlayer mp = new MediaPlayer(media) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } NewsfeedContainer We initialize it lazily to a size that makes sense for the device
  • 8. return BoxLayout.encloseY( titleArea, body, createPostStats(p), buttonBar); } private static Image placeholder; private static Component createMediaComponent(String mime, String id) { if(mime.startsWith("image")) { if(placeholder == null) { placeholder = Image.createImage(getDisplayWidth(), getDisplayHeight() / 2, 0); } ScaleImageButton sb = new ScaleImageButton( URLImage.createCachedImage(id, ServerAPI.mediaUrl(id), placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL)); return sb; } else { try { Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id), true); MediaPlayer mp = new MediaPlayer(media) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } NewsfeedContainer Since the image is scaled in the download process there is no need for the calcPreferredSize trick here, we can just use a regular button or label
  • 9. } ScaleImageButton sb = new ScaleImageButton( URLImage.createCachedImage(id, ServerAPI.mediaUrl(id), placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL)); return sb; } else { try { Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id), true); MediaPlayer mp = new MediaPlayer(media) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; mp.setLoop(true); return mp; } catch(IOException err) { Log.e(err); return new Label("Error loading media"); } } } NewsfeedContainer A media stream can be played directly from our server URL which is pretty darn cool!
  • 10. } ScaleImageButton sb = new ScaleImageButton( URLImage.createCachedImage(id, ServerAPI.mediaUrl(id), placeholder, URLImage.FLAG_RESIZE_SCALE_TO_FILL)); return sb; } else { try { Media media=MediaManager.createMedia(ServerAPI.mediaUrl(id), true); MediaPlayer mp = new MediaPlayer(media) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; mp.setLoop(true); return mp; } catch(IOException err) { Log.e(err); return new Label("Error loading media"); } } } NewsfeedContainer We need to override preferred size here because the media can be any size. This is a bit over simplified. Proper server media handling will transcode the video to multiple form factors and deliver the right video type for every device. This saves bandwidth but also makes sure the media is playable avoiding multiple device related issues.
  • 11. FlowLayout.encloseIn(menu), avatar); titleArea.setUIID("HalfPaddedContainer"); return titleArea; } public static Container createNewsItem(User u, Post p) { Container titleArea = createNewsTitle(u, p); Component body; String style = null; if(p.styling.get() != null && !p.styling.get().equals("Label")) { style = p.styling.get(); } if(p.content.get().indexOf('<') > -1) { if(style != null) { body = new RichTextView(p.content.get(), "PostStyleText"); ((RichTextView)body).setAlignment(CENTER); body.setUIID(style); } else { body = new RichTextView(p.content.get()); body.setUIID("HalfPaddedContainer"); } } else { body = new SpanLabel(p.content.get()); if(style != null) { ((SpanLabel)body).setTextUIID("PostStyleText"); NewsfeedContainer Now that this is in place we can tie it in to the post rendering logic in createNewsItem
  • 12. like.setUIID("CleanButton"); Button comment = new Button("Comment", "CleanButton"); Button share = new Button("Share", "CleanButton"); FontImage.setMaterialIcon(like, FontImage.MATERIAL_THUMB_UP); FontImage.setMaterialIcon(comment, FontImage.MATERIAL_COMMENT); FontImage.setMaterialIcon(share, FontImage.MATERIAL_SHARE); Container buttonBar = GridLayout.encloseIn(3, like, comment, share); buttonBar.setUIID("HalfPaddedContainer"); like.setSelected(p.likes.contains(u)); like.addActionListener(e -> ServerAPI.like(p)); comment.addActionListener(e -> new CommentsForm(p, null).show()); if(p.attachments.size() > 0) { String key = p.attachments.keySet().iterator().next(); return BoxLayout.encloseY(titleArea, body, createMediaComponent(p.attachments.get(key), key), createPostStats(p), buttonBar); } return BoxLayout.encloseY( titleArea, body, createPostStats(p), buttonBar); } NewsfeedContainer If we have an attachment we add the media component to the bottom of the post.
  • 13. like.setUIID("CleanButton"); Button comment = new Button("Comment", "CleanButton"); Button share = new Button("Share", "CleanButton"); FontImage.setMaterialIcon(like, FontImage.MATERIAL_THUMB_UP); FontImage.setMaterialIcon(comment, FontImage.MATERIAL_COMMENT); FontImage.setMaterialIcon(share, FontImage.MATERIAL_SHARE); Container buttonBar = GridLayout.encloseIn(3, like, comment, share); buttonBar.setUIID("HalfPaddedContainer"); like.setSelected(p.likes.contains(u)); like.addActionListener(e -> ServerAPI.like(p)); comment.addActionListener(e -> new CommentsForm(p, null).show()); if(p.attachments.size() > 0) { String key = p.attachments.keySet().iterator().next(); return BoxLayout.encloseY(titleArea, body, createMediaComponent(p.attachments.get(key), key), createPostStats(p), buttonBar); } return BoxLayout.encloseY( titleArea, body, createPostStats(p), buttonBar); } NewsfeedContainer Otherwise we use the same post code as before. With that media posts will work and show up in your feed!
  • 14. titleArea.setUIID("HalfPaddedContainer"); return titleArea; } public static Container createNewsItem(User u, Post p) { Container titleArea = createNewsTitle(u, p); Component body; String style = null; if(p.styling.get() != null && !p.styling.get().equals("Label")) { style = p.styling.get(); } if(p.content.get().indexOf('<') > -1) { if(style != null) { body = new RichTextView(p.content.get(), "PostStyleText"); ((RichTextView)body).setAlignment(CENTER); body.setUIID(style); } else { body = new RichTextView(p.content.get()); body.setUIID("HalfPaddedContainer"); } } else { body = new SpanLabel(p.content.get()); if(style != null) { ((SpanLabel)body).setTextUIID("PostStyleText"); body.setUIID(style); NewsfeedContainer There is however, one additional enhancement I added to the createNewsItem method to support the styled posts which up until now were ignored. I save the result of the if statement here to make the following code shorter/simpler
  • 15. Component body; String style = null; if(p.styling.get() != null && !p.styling.get().equals("Label")) { style = p.styling.get(); } if(p.content.get().indexOf('<') > -1) { if(style != null) { body = new RichTextView(p.content.get(), "PostStyleText"); ((RichTextView)body).setAlignment(CENTER); body.setUIID(style); } else { body = new RichTextView(p.content.get()); body.setUIID("HalfPaddedContainer"); } } else { body = new SpanLabel(p.content.get()); if(style != null) { ((SpanLabel)body).setTextUIID("PostStyleText"); body.setUIID(style); } else { body.setUIID("HalfPaddedContainer"); } } CheckBox like = CheckBox.createToggle("Like"); like.setUIID("CleanButton"); NewsfeedContainer RichTextView now accepts a UIID for the content, I'll go into that code soon. The body is given the background style UIID.
  • 16. Component body; String style = null; if(p.styling.get() != null && !p.styling.get().equals("Label")) { style = p.styling.get(); } if(p.content.get().indexOf('<') > -1) { if(style != null) { body = new RichTextView(p.content.get(), "PostStyleText"); ((RichTextView)body).setAlignment(CENTER); body.setUIID(style); } else { body = new RichTextView(p.content.get()); body.setUIID("HalfPaddedContainer"); } } else { body = new SpanLabel(p.content.get()); if(style != null) { ((SpanLabel)body).setTextUIID("PostStyleText"); body.setUIID(style); } else { body.setUIID("HalfPaddedContainer"); } } CheckBox like = CheckBox.createToggle("Like"); like.setUIID("CleanButton"); NewsfeedContainer The same is true in the `SpanLabel` version of the code...
  • 17. public class RichTextView extends Container { private String text; private float fontSize = 2.6f; private EventDispatcher listeners = new EventDispatcher(); private Font currentFont; private int currentColor = 0; private String currentLink; private Style lastCmp; private Font defaultFont; private Font boldFont; private Font italicFont; private int sizeOfSpace; public RichTextView() { init(null); } public RichTextView(String text, String uiid) { init(uiid); setText(text); } RichTextView This leads us directly to the changes in RichTextView. Because of its nature RichTextView is a bit of a hack without much support for styling. I wanted to give it some generic styling support for the rich posts so this isn't a huge change but it helps… First I had to make fontSize non-final as this will change due to styling:
  • 18. private Font defaultFont; private Font boldFont; private Font italicFont; private int sizeOfSpace; public RichTextView() { init(null); } public RichTextView(String text, String uiid) { init(uiid); setText(text); } public RichTextView(String text) { init(null); setText(text); } private void init(String uiid) { boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize); italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize); if(uiid == null) { defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT, fontSize); } else { RichTextView The next step is simply a change to the constructors and init method. Init now accepts an optional UIID which defaults to null.
  • 19. private Font defaultFont; private Font boldFont; private Font italicFont; private int sizeOfSpace; public RichTextView() { init(null); } public RichTextView(String text, String uiid) { init(uiid); setText(text); } public RichTextView(String text) { init(null); setText(text); } private void init(String uiid) { boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize); italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize); if(uiid == null) { defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT, fontSize); } else { RichTextView We set this UIID in this new constructor but leave it as null in the other cases
  • 20. } public RichTextView(String text) { init(null); setText(text); } private void init(String uiid) { boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize); italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize); if(uiid == null) { defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT, fontSize); } else { Style s = UIManager.getInstance().getComponentStyle(uiid); defaultFont = s.getFont(); boldFont = boldFont.derive(defaultFont.getHeight(), Font.STYLE_BOLD); italicFont = italicFont.derive(defaultFont.getHeight(), Font.STYLE_ITALIC); } sizeOfSpace = defaultFont.charWidth(' '); currentFont = defaultFont; } public void setAlignment(int align) { RichTextView If the UIID isn't set everything acts like it did before...
  • 21. } public RichTextView(String text) { init(null); setText(text); } private void init(String uiid) { boldFont = Font.createTrueTypeFont(NATIVE_MAIN_BOLD, fontSize); italicFont = Font.createTrueTypeFont(NATIVE_ITALIC_LIGHT, fontSize); if(uiid == null) { defaultFont = Font.createTrueTypeFont(NATIVE_MAIN_LIGHT, fontSize); } else { Style s = UIManager.getInstance().getComponentStyle(uiid); defaultFont = s.getFont(); boldFont = boldFont.derive(defaultFont.getHeight(), Font.STYLE_BOLD); italicFont = italicFont.derive(defaultFont.getHeight(), Font.STYLE_ITALIC); } sizeOfSpace = defaultFont.charWidth(' '); currentFont = defaultFont; } public void setAlignment(int align) { RichTextView Otherwise we get the default font from the style then resize the bold/italic fonts to match its size. That's it, we can now style the default font of the rich text view.