SlideShare a Scribd company logo
1 of 28
Download to read offline
Creating a Facebook Clone - Part XLI
We are now ready for the NewPostForm changes
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
private TextArea post = new TextArea(3, 80);
private String postStyleValue;
private String attachment;
private String mime;
private Button postButton;
private NewPostForm() {
super("Create Post", new BorderLayout());
}
private void initUI(Container postStyles) {
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
Command c = getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> post(current));
postButton = getToolbar().findCommandComponent(c);
NewPostForm
Up until now the changes were simple but in this class we have a bit of work to do. Lets start with the top level changes.

Currently we support one attachment, this field represents the attachment id
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
private TextArea post = new TextArea(3, 80);
private String postStyleValue;
private String attachment;
private String mime;
private Button postButton;
private NewPostForm() {
super("Create Post", new BorderLayout());
}
private void initUI(Container postStyles) {
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
Command c = getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> post(current));
postButton = getToolbar().findCommandComponent(c);
NewPostForm
This is the attachment mime type if applicable
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
private TextArea post = new TextArea(3, 80);
private String postStyleValue;
private String attachment;
private String mime;
private Button postButton;
private NewPostForm() {
super("Create Post", new BorderLayout());
}
private void initUI(Container postStyles) {
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
Command c = getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> post(current));
postButton = getToolbar().findCommandComponent(c);
NewPostForm
This is the button for sending a post we need to disable this button until the attachment is uploaded
public class NewPostForm extends Form {
private static final String[] POST_STYLES = {
"Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack",
"PostStyleRed", "PostStylePurple" };
private TextArea post = new TextArea(3, 80);
private String postStyleValue;
private String attachment;
private String mime;
private Button postButton;
private NewPostForm() {
super("Create Post", new BorderLayout());
}
private void initUI(Container postStyles) {
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
Command c = getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> post(current));
postButton = getToolbar().findCommandComponent(c);
NewPostForm
The constructor is now private as the class is instantiated via factory methods. Also notice we don't invoke initUI() in the constructor anymore!ā€Ø
The first big change is the initUI method which up until now created the same UI and was bound in the constructor. This will no longer work as the UI with an attachment
will be slightly diļ¬€erent. This code is still there it just moved to the factory method.
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
add(NORTH, userSettings);
post.setUIID("Label");
post.setGrowByContent(false);
Component l;
if(postStyles != null) {
l = LayeredLayout.encloseIn(
BorderLayout.north(post), postStyles);
} else {
l = post;
}
add(CENTER, l);
setEditOnShow(post);
}
public static NewPostForm createPost() {
NewPostForm n = new NewPostForm();
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
NewPostForm
Hereā€¦
userSettings.add(CENTER,
BoxLayout.encloseY(
new Label(me.fullName(), "MultiLine1"),
FlowLayout.encloseIn(friends)));
add(NORTH, userSettings);
post.setUIID("Label");
post.setGrowByContent(false);
Component l;
if(postStyles != null) {
l = LayeredLayout.encloseIn(
BorderLayout.north(post), postStyles);
} else {
l = post;
}
add(CENTER, l);
setEditOnShow(post);
}
public static NewPostForm createPost() {
NewPostForm n = new NewPostForm();
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
NewPostForm
The postStyles code happened at the end of initUI originally but due to logistics we need it here.

This allows the image & video versions to avoid the styles bar at the bottom of the UI. Notice that those don't exist in the native Facebook app either.
private Button postButton;
private NewPostForm() {
super("Create Post", new BorderLayout());
}
private void initUI(Container postStyles) {
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
Command c = getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> post(current));
postButton = getToolbar().findCommandComponent(c);
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);
post.setUIID("Label");
post.setGrowByContent(false);
NewPostForm
Which brings us back to the initUI method
private Button postButton;
private NewPostForm() {
super("Create Post", new BorderLayout());
}
private void initUI(Container postStyles) {
Form current = getCurrentForm();
getToolbar().setBackCommand("Cancel",
Toolbar.BackCommandPolicy.
WHEN_USES_TITLE_OTHERWISE_ARROW,
e -> current.showBack());
Command c = getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> post(current));
postButton = getToolbar().findCommandComponent(c);
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);
post.setUIID("Label");
post.setGrowByContent(false);
NewPostForm
This is the button for posting from the toolbar, we can later disable this button. We can find the button for toolbar commands to get low level control
Command c = getToolbar().addMaterialCommandToRightBar("",
FontImage.MATERIAL_DONE, e -> post(current));
postButton = getToolbar().findCommandComponent(c);
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);
post.setUIID("Label");
post.setGrowByContent(false);
Component l;
if(postStyles != null) {
l = LayeredLayout.encloseIn(
BorderLayout.north(post), postStyles);
} else {
l = post;
}
add(CENTER, l);
setEditOnShow(post);
}
NewPostForm
This code will behave exactly the same as it did before if postStyles has a value and will just add the post to center if it doesn't
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
n.mime = "image/jpeg";
ScaleImageLabel i = new ScaleImageLabel(img) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
Slider s = n.upload(p);
n.add(SOUTH, LayeredLayout.encloseIn(
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
NewPostForm
Those are somewhat nuanced changes that expose components we can work with. Lets see how this allows image uploads in the main method. ā€Ø
This is a factory method for an image post.
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
n.mime = "image/jpeg";
ScaleImageLabel i = new ScaleImageLabel(img) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
Slider s = n.upload(p);
n.add(SOUTH, LayeredLayout.encloseIn(
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
NewPostForm
The style bar in the bottom isn't included
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
n.mime = "image/jpeg";
ScaleImageLabel i = new ScaleImageLabel(img) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
Slider s = n.upload(p);
n.add(SOUTH, LayeredLayout.encloseIn(
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
NewPostForm
We set the mime type here, but notice we don't know the media ID yet so the attachment value isn't set!
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
n.mime = "image/jpeg";
ScaleImageLabel i = new ScaleImageLabel(img) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
Slider s = n.upload(p);
n.add(SOUTH, LayeredLayout.encloseIn(
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
NewPostForm
The image will take up half the screen height, this is better than using an API like setPreferredSize because it will still work if the device is rotated
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
n.mime = "image/jpeg";
ScaleImageLabel i = new ScaleImageLabel(img) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
Slider s = n.upload(p);
n.add(SOUTH, LayeredLayout.encloseIn(
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
NewPostForm
Here we upload the media to the server and return a Slider component to track the upload progress
Container postStyles = n.createPostStyles(n.post);
n.initUI(BorderLayout.south(postStyles));
return n;
}
public static NewPostForm createImagePost(EncodedImage img,
ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
n.mime = "image/jpeg";
ScaleImageLabel i = new ScaleImageLabel(img) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
Slider s = n.upload(p);
n.add(SOUTH, LayeredLayout.encloseIn(
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
NewPostForm
We place the image on the bottom of the form and the slider progress on top of it further down.ā€Ø
Before we go to the logical next step in the upload method I'd like to point out a big missing piece: delete. If we close this post now the image would still be in the
servers and no one would know... ā€Ø
That's a flaw I left in place due to time constraints. There are several potential fixes, probably the best one would be a backend server process that deletes media that
has no references. 

We can also add a delete WebService but that wouldn't work perfectly for cases of app crashes etc.
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
return n;
}
private Slider upload(ImagePicker p) {
postButton.setEnabled(false);
Slider s = new Slider();
MultipartRequest m = p.upload(e -> {
attachment = e;
postButton.setEnabled(true);
});
SliderBridge.bindProgress(m, s);
return s;
}
NewPostForm
Iā€™ll come back to the video post code soon. For now I'll skip ahead to the upload method.
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
return n;
}
private Slider upload(ImagePicker p) {
postButton.setEnabled(false);
Slider s = new Slider();
MultipartRequest m = p.upload(e -> {
attachment = e;
postButton.setEnabled(true);
});
SliderBridge.bindProgress(m, s);
return s;
}
NewPostForm
If we're uploading a media file the post button should be disabled until we are done
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
return n;
}
private Slider upload(ImagePicker p) {
postButton.setEnabled(false);
Slider s = new Slider();
MultipartRequest m = p.upload(e -> {
attachment = e;
postButton.setEnabled(true);
});
SliderBridge.bindProgress(m, s);
return s;
}
NewPostForm
Once upload finished we enable the post button, notice we save the attachment value too which we will need later
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
return n;
}
private Slider upload(ImagePicker p) {
postButton.setEnabled(false);
Slider s = new Slider();
MultipartRequest m = p.upload(e -> {
attachment = e;
postButton.setEnabled(true);
});
SliderBridge.bindProgress(m, s);
return s;
}
NewPostForm
You can bind a connection request to a slider using this utility class builtin to Codename One.

Every stream in Codename One is observable which means we can get update events on any IO operation seamlessly. Utilities like SliderBridge take this to the next
logical step by binding the progress events from NetworkManager to a Slider.
attachment = e;
postButton.setEnabled(true);
});
SliderBridge.bindProgress(m, s);
return s;
}
private void post(Form previousForm) {
Dialog dlg = new InfiniteProgress().showInifiniteBlocking();
Post p = new Post().
content.set(post.getText()).
visibility.set("public").
styling.set(postStyleValue);
if(attachment != null) {
p.attachments.put(attachment, mime);
}
if(!ServerAPI.post(p)) {
dlg.dispose();
ToastBar.showErrorMessage("Error posting to server");
return;
}
previousForm.showBack();
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
NewPostForm
With this lets go directly to the changes in post to support attachmentsā€¦ā€Ø
This code had to move outside of the if statement even though it hasn't changed
attachment = e;
postButton.setEnabled(true);
});
SliderBridge.bindProgress(m, s);
return s;
}
private void post(Form previousForm) {
Dialog dlg = new InfiniteProgress().showInifiniteBlocking();
Post p = new Post().
content.set(post.getText()).
visibility.set("public").
styling.set(postStyleValue);
if(attachment != null) {
p.attachments.put(attachment, mime);
}
if(!ServerAPI.post(p)) {
dlg.dispose();
ToastBar.showErrorMessage("Error posting to server");
return;
}
previousForm.showBack();
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
NewPostForm
If we have an attachment we add it to the post object
attachment = e;
postButton.setEnabled(true);
});
SliderBridge.bindProgress(m, s);
return s;
}
private void post(Form previousForm) {
Dialog dlg = new InfiniteProgress().showInifiniteBlocking();
Post p = new Post().
content.set(post.getText()).
visibility.set("public").
styling.set(postStyleValue);
if(attachment != null) {
p.attachments.put(attachment, mime);
}
if(!ServerAPI.post(p)) {
dlg.dispose();
ToastBar.showErrorMessage("Error posting to server");
return;
}
previousForm.showBack();
}
private Container createPostStyles(TextArea post) {
Container postStyles = new Container(BoxLayout.x());
NewPostForm
After this line the rest of the code is identical. With that image posting should work although we still need to update the callers to use the factory methods instead of the
constructor.
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
Slider s = n.upload(p);
n.mime = "video/mp4";
Container videoContainer = new Container(new LayeredLayout()) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
NewPostForm
We have one final change to the NewPostForm, the createVideoPost method
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
Slider s = n.upload(p);
n.mime = "video/mp4";
Container videoContainer = new Container(new LayeredLayout()) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
NewPostForm
Most of this looks just like the createImagePost method with minor changes such as mp4 instead of jpeg etc.
i, BorderLayout.south(s)));
return n;
}
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
Slider s = n.upload(p);
n.mime = "video/mp4";
Container videoContainer = new Container(new LayeredLayout()) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
NewPostForm
We can't override the preferred size of the video component but we can place it in a Container where we do override the size
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
Slider s = n.upload(p);
n.mime = "video/mp4";
Container videoContainer = new Container(new LayeredLayout()) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
return n;
}
NewPostForm
We need that container anyway so we can place a progress indicator on top of that to show the upload progress
public static NewPostForm createVideoPost(Media m, ImagePicker p) {
NewPostForm n = new NewPostForm();
n.initUI(null);
Slider s = n.upload(p);
n.mime = "video/mp4";
Container videoContainer = new Container(new LayeredLayout()) {
@Override
protected Dimension calcPreferredSize() {
return new Dimension(getDisplayWidth(),
getDisplayHeight() / 2);
}
};
videoContainer.add(m.getVideoComponent());
videoContainer.add(BorderLayout.south(s));
n.add(SOUTH, videoContainer);
n.addShowListener(e -> {
m.play();
m.setVolume(0);
m.setTime(Math.min(m.getDuration() / 2, 1000));
m.pause();
});
return n;
}
NewPostForm
This shows a frame of the video 1 second into playback. Notice I invoke play() and only then try seeking, without doing that the behavior is undefined for some features
such as seek.

With that the NewPostForm is done we just need to wire it in.

More Related Content

Similar to Creating a Facebook Clone - Part XLI - 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.pdfShaiAlmog1
Ā 
Creating a Facebook Clone - Part XXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXVIII - Transcript.pdfCreating a Facebook Clone - Part XXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXVIII - Transcript.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
Initial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdfInitial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdfShaiAlmog1
Ā 
Creating a Facebook Clone - Part XXXV.pdf
Creating a Facebook Clone - Part XXXV.pdfCreating a Facebook Clone - Part XXXV.pdf
Creating a Facebook Clone - Part XXXV.pdfShaiAlmog1
Ā 
2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdf
2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdf2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdf
2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdfallwayscollection
Ā 
Creating a Facebook Clone - Part IV.pdf
Creating a Facebook Clone - Part IV.pdfCreating a Facebook Clone - Part IV.pdf
Creating a Facebook Clone - Part IV.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
Creating a Facebook Clone - Part XLII - Transcript.pdf
Creating a Facebook Clone - Part XLII - Transcript.pdfCreating a Facebook Clone - Part XLII - Transcript.pdf
Creating a Facebook Clone - Part XLII - Transcript.pdfShaiAlmog1
Ā 
Creating a Facebook Clone - Part XXXV - Transcript.pdf
Creating a Facebook Clone - Part XXXV - Transcript.pdfCreating a Facebook Clone - Part XXXV - Transcript.pdf
Creating a Facebook Clone - Part XXXV - Transcript.pdfShaiAlmog1
Ā 
Creating an Uber Clone - Part XXXIX.pdf
Creating an Uber Clone - Part XXXIX.pdfCreating an Uber Clone - Part XXXIX.pdf
Creating an Uber Clone - Part XXXIX.pdfShaiAlmog1
Ā 
Creating a Facebook Clone - Part XLVI.pdf
Creating a Facebook Clone - Part XLVI.pdfCreating a Facebook Clone - Part XLVI.pdf
Creating a Facebook Clone - Part XLVI.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
Creating a Facebook Clone - Part XI.pdf
Creating a Facebook Clone - Part XI.pdfCreating a Facebook Clone - Part XI.pdf
Creating a Facebook Clone - Part XI.pdfShaiAlmog1
Ā 
Initial UI Mockup - Part 3 - Transcript.pdf
Initial UI Mockup - Part 3 - Transcript.pdfInitial UI Mockup - Part 3 - Transcript.pdf
Initial UI Mockup - Part 3 - Transcript.pdfShaiAlmog1
Ā 
Creating an Uber Clone - Part V - Transcript.pdf
Creating an Uber Clone - Part V - Transcript.pdfCreating an Uber Clone - Part V - Transcript.pdf
Creating an Uber Clone - Part V - Transcript.pdfShaiAlmog1
Ā 
Creating a Facebook Clone - Part XLVI - Transcript.pdf
Creating a Facebook Clone - Part XLVI - Transcript.pdfCreating a Facebook Clone - Part XLVI - Transcript.pdf
Creating a Facebook Clone - Part XLVI - Transcript.pdfShaiAlmog1
Ā 
Extracting ui Design - part 6 - transcript.pdf
Extracting ui Design - part 6 - transcript.pdfExtracting ui Design - part 6 - transcript.pdf
Extracting ui Design - part 6 - transcript.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 

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

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 XXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXVIII - Transcript.pdfCreating a Facebook Clone - Part XXVIII - Transcript.pdf
Creating a Facebook Clone - Part XXVIII - Transcript.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
Ā 
Initial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdfInitial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdf
Ā 
Creating a Facebook Clone - Part XXXV.pdf
Creating a Facebook Clone - Part XXXV.pdfCreating a Facebook Clone - Part XXXV.pdf
Creating a Facebook Clone - Part XXXV.pdf
Ā 
2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdf
2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdf2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdf
2. Section 2. Implementing functionality in the PersonEntry. (1.5 ma.pdf
Ā 
Creating a Facebook Clone - Part IV.pdf
Creating a Facebook Clone - Part IV.pdfCreating a Facebook Clone - Part IV.pdf
Creating a Facebook Clone - Part IV.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
Ā 
Creating a Facebook Clone - Part XLII - Transcript.pdf
Creating a Facebook Clone - Part XLII - Transcript.pdfCreating a Facebook Clone - Part XLII - Transcript.pdf
Creating a Facebook Clone - Part XLII - Transcript.pdf
Ā 
Creating a Facebook Clone - Part XXXV - Transcript.pdf
Creating a Facebook Clone - Part XXXV - Transcript.pdfCreating a Facebook Clone - Part XXXV - Transcript.pdf
Creating a Facebook Clone - Part XXXV - Transcript.pdf
Ā 
Creating an Uber Clone - Part XXXIX.pdf
Creating an Uber Clone - Part XXXIX.pdfCreating an Uber Clone - Part XXXIX.pdf
Creating an Uber Clone - Part XXXIX.pdf
Ā 
Creating a Facebook Clone - Part XLVI.pdf
Creating a Facebook Clone - Part XLVI.pdfCreating a Facebook Clone - Part XLVI.pdf
Creating a Facebook Clone - Part XLVI.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 XI.pdf
Creating a Facebook Clone - Part XI.pdfCreating a Facebook Clone - Part XI.pdf
Creating a Facebook Clone - Part XI.pdf
Ā 
Initial UI Mockup - Part 3 - Transcript.pdf
Initial UI Mockup - Part 3 - Transcript.pdfInitial UI Mockup - Part 3 - Transcript.pdf
Initial UI Mockup - Part 3 - Transcript.pdf
Ā 
Creating an Uber Clone - Part V - Transcript.pdf
Creating an Uber Clone - Part V - Transcript.pdfCreating an Uber Clone - Part V - Transcript.pdf
Creating an Uber Clone - Part V - Transcript.pdf
Ā 
Creating a Facebook Clone - Part XLVI - Transcript.pdf
Creating a Facebook Clone - Part XLVI - Transcript.pdfCreating a Facebook Clone - Part XLVI - Transcript.pdf
Creating a Facebook Clone - Part XLVI - Transcript.pdf
Ā 
Extracting ui Design - part 6 - transcript.pdf
Extracting ui Design - part 6 - transcript.pdfExtracting ui Design - part 6 - transcript.pdf
Extracting ui Design - part 6 - transcript.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
Ā 
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
Ā 

More from ShaiAlmog1

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 ...ShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 
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.pdfShaiAlmog1
Ā 

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-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.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
Ā 

Recently uploaded

"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
Ā 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
Ā 
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 FMESafe Software
Ā 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
Ā 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusZilliz
Ā 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
Ā 
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
Ā 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
Ā 
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, Adobeapidays
Ā 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
Ā 
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 WoodJuan lago vƔzquez
Ā 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
Ā 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
Ā 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKJago de Vreede
Ā 
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...Jeffrey Haguewood
Ā 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
Ā 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
Ā 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
Ā 
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.pdfOrbitshub
Ā 

Recently uploaded (20)

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
Ā 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
Ā 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
Ā 
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 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Ā 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
Ā 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 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...
Ā 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
Ā 
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
Ā 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.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
Ā 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
Ā 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
Ā 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Ā 
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...
Ā 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
Ā 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
Ā 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
Ā 
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
Ā 

Creating a Facebook Clone - Part XLI - Transcript.pdf

  • 1. Creating a Facebook Clone - Part XLI We are now ready for the NewPostForm changes
  • 2. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; private TextArea post = new TextArea(3, 80); private String postStyleValue; private String attachment; private String mime; private Button postButton; private NewPostForm() { super("Create Post", new BorderLayout()); } private void initUI(Container postStyles) { Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); Command c = getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> post(current)); postButton = getToolbar().findCommandComponent(c); NewPostForm Up until now the changes were simple but in this class we have a bit of work to do. Lets start with the top level changes. Currently we support one attachment, this field represents the attachment id
  • 3. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; private TextArea post = new TextArea(3, 80); private String postStyleValue; private String attachment; private String mime; private Button postButton; private NewPostForm() { super("Create Post", new BorderLayout()); } private void initUI(Container postStyles) { Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); Command c = getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> post(current)); postButton = getToolbar().findCommandComponent(c); NewPostForm This is the attachment mime type if applicable
  • 4. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; private TextArea post = new TextArea(3, 80); private String postStyleValue; private String attachment; private String mime; private Button postButton; private NewPostForm() { super("Create Post", new BorderLayout()); } private void initUI(Container postStyles) { Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); Command c = getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> post(current)); postButton = getToolbar().findCommandComponent(c); NewPostForm This is the button for sending a post we need to disable this button until the attachment is uploaded
  • 5. public class NewPostForm extends Form { private static final String[] POST_STYLES = { "Label", "PostStyleHearts", "PostStyleHands", "PostStyleBlack", "PostStyleRed", "PostStylePurple" }; private TextArea post = new TextArea(3, 80); private String postStyleValue; private String attachment; private String mime; private Button postButton; private NewPostForm() { super("Create Post", new BorderLayout()); } private void initUI(Container postStyles) { Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); Command c = getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> post(current)); postButton = getToolbar().findCommandComponent(c); NewPostForm The constructor is now private as the class is instantiated via factory methods. Also notice we don't invoke initUI() in the constructor anymore!ā€Ø The first big change is the initUI method which up until now created the same UI and was bound in the constructor. This will no longer work as the UI with an attachment will be slightly diļ¬€erent. This code is still there it just moved to the factory method.
  • 6. userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); add(NORTH, userSettings); post.setUIID("Label"); post.setGrowByContent(false); Component l; if(postStyles != null) { l = LayeredLayout.encloseIn( BorderLayout.north(post), postStyles); } else { l = post; } add(CENTER, l); setEditOnShow(post); } public static NewPostForm createPost() { NewPostForm n = new NewPostForm(); Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, NewPostForm Hereā€¦
  • 7. userSettings.add(CENTER, BoxLayout.encloseY( new Label(me.fullName(), "MultiLine1"), FlowLayout.encloseIn(friends))); add(NORTH, userSettings); post.setUIID("Label"); post.setGrowByContent(false); Component l; if(postStyles != null) { l = LayeredLayout.encloseIn( BorderLayout.north(post), postStyles); } else { l = post; } add(CENTER, l); setEditOnShow(post); } public static NewPostForm createPost() { NewPostForm n = new NewPostForm(); Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, NewPostForm The postStyles code happened at the end of initUI originally but due to logistics we need it here. This allows the image & video versions to avoid the styles bar at the bottom of the UI. Notice that those don't exist in the native Facebook app either.
  • 8. private Button postButton; private NewPostForm() { super("Create Post", new BorderLayout()); } private void initUI(Container postStyles) { Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); Command c = getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> post(current)); postButton = getToolbar().findCommandComponent(c); 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); post.setUIID("Label"); post.setGrowByContent(false); NewPostForm Which brings us back to the initUI method
  • 9. private Button postButton; private NewPostForm() { super("Create Post", new BorderLayout()); } private void initUI(Container postStyles) { Form current = getCurrentForm(); getToolbar().setBackCommand("Cancel", Toolbar.BackCommandPolicy. WHEN_USES_TITLE_OTHERWISE_ARROW, e -> current.showBack()); Command c = getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> post(current)); postButton = getToolbar().findCommandComponent(c); 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); post.setUIID("Label"); post.setGrowByContent(false); NewPostForm This is the button for posting from the toolbar, we can later disable this button. We can find the button for toolbar commands to get low level control
  • 10. Command c = getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_DONE, e -> post(current)); postButton = getToolbar().findCommandComponent(c); 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); post.setUIID("Label"); post.setGrowByContent(false); Component l; if(postStyles != null) { l = LayeredLayout.encloseIn( BorderLayout.north(post), postStyles); } else { l = post; } add(CENTER, l); setEditOnShow(post); } NewPostForm This code will behave exactly the same as it did before if postStyles has a value and will just add the post to center if it doesn't
  • 11. Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); n.mime = "image/jpeg"; ScaleImageLabel i = new ScaleImageLabel(img) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; Slider s = n.upload(p); n.add(SOUTH, LayeredLayout.encloseIn( i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); NewPostForm Those are somewhat nuanced changes that expose components we can work with. Lets see how this allows image uploads in the main method. ā€Ø This is a factory method for an image post.
  • 12. Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); n.mime = "image/jpeg"; ScaleImageLabel i = new ScaleImageLabel(img) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; Slider s = n.upload(p); n.add(SOUTH, LayeredLayout.encloseIn( i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); NewPostForm The style bar in the bottom isn't included
  • 13. Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); n.mime = "image/jpeg"; ScaleImageLabel i = new ScaleImageLabel(img) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; Slider s = n.upload(p); n.add(SOUTH, LayeredLayout.encloseIn( i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); NewPostForm We set the mime type here, but notice we don't know the media ID yet so the attachment value isn't set!
  • 14. Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); n.mime = "image/jpeg"; ScaleImageLabel i = new ScaleImageLabel(img) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; Slider s = n.upload(p); n.add(SOUTH, LayeredLayout.encloseIn( i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); NewPostForm The image will take up half the screen height, this is better than using an API like setPreferredSize because it will still work if the device is rotated
  • 15. Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); n.mime = "image/jpeg"; ScaleImageLabel i = new ScaleImageLabel(img) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; Slider s = n.upload(p); n.add(SOUTH, LayeredLayout.encloseIn( i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); NewPostForm Here we upload the media to the server and return a Slider component to track the upload progress
  • 16. Container postStyles = n.createPostStyles(n.post); n.initUI(BorderLayout.south(postStyles)); return n; } public static NewPostForm createImagePost(EncodedImage img, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); n.mime = "image/jpeg"; ScaleImageLabel i = new ScaleImageLabel(img) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; Slider s = n.upload(p); n.add(SOUTH, LayeredLayout.encloseIn( i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); NewPostForm We place the image on the bottom of the form and the slider progress on top of it further down.ā€Ø Before we go to the logical next step in the upload method I'd like to point out a big missing piece: delete. If we close this post now the image would still be in the servers and no one would know... ā€Ø That's a flaw I left in place due to time constraints. There are several potential fixes, probably the best one would be a backend server process that deletes media that has no references. We can also add a delete WebService but that wouldn't work perfectly for cases of app crashes etc.
  • 17. } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); return n; } private Slider upload(ImagePicker p) { postButton.setEnabled(false); Slider s = new Slider(); MultipartRequest m = p.upload(e -> { attachment = e; postButton.setEnabled(true); }); SliderBridge.bindProgress(m, s); return s; } NewPostForm Iā€™ll come back to the video post code soon. For now I'll skip ahead to the upload method.
  • 18. } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); return n; } private Slider upload(ImagePicker p) { postButton.setEnabled(false); Slider s = new Slider(); MultipartRequest m = p.upload(e -> { attachment = e; postButton.setEnabled(true); }); SliderBridge.bindProgress(m, s); return s; } NewPostForm If we're uploading a media file the post button should be disabled until we are done
  • 19. } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); return n; } private Slider upload(ImagePicker p) { postButton.setEnabled(false); Slider s = new Slider(); MultipartRequest m = p.upload(e -> { attachment = e; postButton.setEnabled(true); }); SliderBridge.bindProgress(m, s); return s; } NewPostForm Once upload finished we enable the post button, notice we save the attachment value too which we will need later
  • 20. } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); return n; } private Slider upload(ImagePicker p) { postButton.setEnabled(false); Slider s = new Slider(); MultipartRequest m = p.upload(e -> { attachment = e; postButton.setEnabled(true); }); SliderBridge.bindProgress(m, s); return s; } NewPostForm You can bind a connection request to a slider using this utility class builtin to Codename One. Every stream in Codename One is observable which means we can get update events on any IO operation seamlessly. Utilities like SliderBridge take this to the next logical step by binding the progress events from NetworkManager to a Slider.
  • 21. attachment = e; postButton.setEnabled(true); }); SliderBridge.bindProgress(m, s); return s; } private void post(Form previousForm) { Dialog dlg = new InfiniteProgress().showInifiniteBlocking(); Post p = new Post(). content.set(post.getText()). visibility.set("public"). styling.set(postStyleValue); if(attachment != null) { p.attachments.put(attachment, mime); } if(!ServerAPI.post(p)) { dlg.dispose(); ToastBar.showErrorMessage("Error posting to server"); return; } previousForm.showBack(); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); NewPostForm With this lets go directly to the changes in post to support attachmentsā€¦ā€Ø This code had to move outside of the if statement even though it hasn't changed
  • 22. attachment = e; postButton.setEnabled(true); }); SliderBridge.bindProgress(m, s); return s; } private void post(Form previousForm) { Dialog dlg = new InfiniteProgress().showInifiniteBlocking(); Post p = new Post(). content.set(post.getText()). visibility.set("public"). styling.set(postStyleValue); if(attachment != null) { p.attachments.put(attachment, mime); } if(!ServerAPI.post(p)) { dlg.dispose(); ToastBar.showErrorMessage("Error posting to server"); return; } previousForm.showBack(); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); NewPostForm If we have an attachment we add it to the post object
  • 23. attachment = e; postButton.setEnabled(true); }); SliderBridge.bindProgress(m, s); return s; } private void post(Form previousForm) { Dialog dlg = new InfiniteProgress().showInifiniteBlocking(); Post p = new Post(). content.set(post.getText()). visibility.set("public"). styling.set(postStyleValue); if(attachment != null) { p.attachments.put(attachment, mime); } if(!ServerAPI.post(p)) { dlg.dispose(); ToastBar.showErrorMessage("Error posting to server"); return; } previousForm.showBack(); } private Container createPostStyles(TextArea post) { Container postStyles = new Container(BoxLayout.x()); NewPostForm After this line the rest of the code is identical. With that image posting should work although we still need to update the callers to use the factory methods instead of the constructor.
  • 24. i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); Slider s = n.upload(p); n.mime = "video/mp4"; Container videoContainer = new Container(new LayeredLayout()) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); NewPostForm We have one final change to the NewPostForm, the createVideoPost method
  • 25. i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); Slider s = n.upload(p); n.mime = "video/mp4"; Container videoContainer = new Container(new LayeredLayout()) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); NewPostForm Most of this looks just like the createImagePost method with minor changes such as mp4 instead of jpeg etc.
  • 26. i, BorderLayout.south(s))); return n; } public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); Slider s = n.upload(p); n.mime = "video/mp4"; Container videoContainer = new Container(new LayeredLayout()) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); NewPostForm We can't override the preferred size of the video component but we can place it in a Container where we do override the size
  • 27. public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); Slider s = n.upload(p); n.mime = "video/mp4"; Container videoContainer = new Container(new LayeredLayout()) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); return n; } NewPostForm We need that container anyway so we can place a progress indicator on top of that to show the upload progress
  • 28. public static NewPostForm createVideoPost(Media m, ImagePicker p) { NewPostForm n = new NewPostForm(); n.initUI(null); Slider s = n.upload(p); n.mime = "video/mp4"; Container videoContainer = new Container(new LayeredLayout()) { @Override protected Dimension calcPreferredSize() { return new Dimension(getDisplayWidth(), getDisplayHeight() / 2); } }; videoContainer.add(m.getVideoComponent()); videoContainer.add(BorderLayout.south(s)); n.add(SOUTH, videoContainer); n.addShowListener(e -> { m.play(); m.setVolume(0); m.setTime(Math.min(m.getDuration() / 2, 1000)); m.pause(); }); return n; } NewPostForm This shows a frame of the video 1 second into playback. Notice I invoke play() and only then try seeking, without doing that the behavior is undefined for some features such as seek. With that the NewPostForm is done we just need to wire it in.