SlideShare a Scribd company logo
Creating a Facebook Clone - Part X
There is a fine line between doing a mockup and implementing a data model. Once we have a UI in place designing the underlying data model becomes a puzzle of filling
in the missing pieces. Before we go into the newsfeed I'd like to create the objects that represent users and posts. Having these in place will make things easier when we
want to implement the server.
User
✦First Name
✦Family Name
✦Email
✦Phone
✦Gender
✦Birthday
© Codename One 2017 all rights reserved
We'll use property objects which make server communication & caching trivial. First we'll start with the User object. We will need a new package to separate the data
model, I went with: com.codename1.fbclone.data. So what do we need for a user? A lot of these things are obvious from the signup UI:

* First name

* FamilyName

* Email

* Phone

* Gender

* Birthday
public class User implements PropertyBusinessObject {
public final Property<String, User> id = new Property<>("id");
public final Property<String, User>
firstName = new Property<>("firstName");
public final Property<String, User>
familyName = new Property<>("familyName");
public final Property<String, User> email = new Property<>("email");
public final Property<String, User> phone = new Property<>("phone");
public final Property<String, User> gender = new Property<>("gender");
public final LongProperty<User> birthday =
new LongProperty<>("birthday");
public final Property<String, User> avatar = new Property<>("avatar");
private final PropertyIndex idx = new PropertyIndex(this, "User",
id, firstName, familyName, email, phone, gender, avatar,
birthday);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
public String fullName() {
return firstName.get() + " " + familyName.get();
}
User
We also need a unique id, since security is crucial I will go with a string based unique id.

We also need a picture of the user to show next to his posts so an avatar entry will also help. This is all easy to express in a business object class.

These properties match the things we said we needed to know about a user
public class User implements PropertyBusinessObject {
public final Property<String, User> id = new Property<>("id");
public final Property<String, User>
firstName = new Property<>("firstName");
public final Property<String, User>
familyName = new Property<>("familyName");
public final Property<String, User> email = new Property<>("email");
public final Property<String, User> phone = new Property<>("phone");
public final Property<String, User> gender = new Property<>("gender");
public final LongProperty<User> birthday =
new LongProperty<>("birthday");
public final Property<String, User> avatar = new Property<>("avatar");
private final PropertyIndex idx = new PropertyIndex(this, "User",
id, firstName, familyName, email, phone, gender, avatar,
birthday);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
public String fullName() {
return firstName.get() + " " + familyName.get();
}
User
Dates are easy to store as long values since epoch
new LongProperty<>("birthday");
public final Property<String, User> avatar = new Property<>("avatar");
private final PropertyIndex idx = new PropertyIndex(this, "User",
id, firstName, familyName, email, phone, gender, avatar,
birthday);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
public String fullName() {
return firstName.get() + " " + familyName.get();
}
public Image getAvatar(float imageSize) {
String filename = "round-avatar-" + imageSize + "-" + id.get();
if(existsInStorage(filename)) {
try(InputStream is = createStorageInputStream(filename);) {
return Image.createImage(is);
} catch(IOException err) {
Log.e(err);
deleteStorageFile(filename);
}
}
int size = convertToPixels(imageSize);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
User
Getting the full name is a pretty common thing so it makes sense to provide this helper method.
new LongProperty<>("birthday");
public final Property<String, User> avatar = new Property<>("avatar");
private final PropertyIndex idx = new PropertyIndex(this, "User",
id, firstName, familyName, email, phone, gender, avatar,
birthday);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
public String fullName() {
return firstName.get() + " " + familyName.get();
}
public Image getAvatar(float imageSize) {
String filename = "round-avatar-" + imageSize + "-" + id.get();
if(existsInStorage(filename)) {
try(InputStream is = createStorageInputStream(filename);) {
return Image.createImage(is);
} catch(IOException err) {
Log.e(err);
deleteStorageFile(filename);
}
}
int size = convertToPixels(imageSize);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
User
Everything about this class is really simple except for the avatar. It should point at an image URL but how would we use it?

To simplify that I'll add a getAvatar method to User that will include the functionality of fetching/caching/resizing and shaping the avatar image.

The method accepts the image size in millimeters and returns an Image that matches that size
new LongProperty<>("birthday");
public final Property<String, User> avatar = new Property<>("avatar");
private final PropertyIndex idx = new PropertyIndex(this, "User",
id, firstName, familyName, email, phone, gender, avatar,
birthday);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
public String fullName() {
return firstName.get() + " " + familyName.get();
}
public Image getAvatar(float imageSize) {
String filename = "round-avatar-" + imageSize + "-" + id.get();
if(existsInStorage(filename)) {
try(InputStream is = createStorageInputStream(filename)) {
return Image.createImage(is);
} catch(IOException err) {
Log.e(err);
deleteStorageFile(filename);
}
}
int size = convertToPixels(imageSize);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
User
If we have an image in cache for this user we'll return that image
new LongProperty<>("birthday");
public final Property<String, User> avatar = new Property<>("avatar");
private final PropertyIndex idx = new PropertyIndex(this, "User",
id, firstName, familyName, email, phone, gender, avatar,
birthday);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
public String fullName() {
return firstName.get() + " " + familyName.get();
}
public Image getAvatar(float imageSize) {
String filename = "round-avatar-" + imageSize + "-" + id.get();
if(existsInStorage(filename)) {
try(InputStream is = createStorageInputStream(filename)) {
return Image.createImage(is);
} catch(IOException err) {
Log.e(err);
deleteStorageFile(filename);
}
}
int size = convertToPixels(imageSize);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
User
We load the image from storage, if loading failed due to corrupt image we'll delete the image file so the next call to this method will re-create it
if(existsInStorage(filename)) {
try(InputStream is = createStorageInputStream(filename)) {
return Image.createImage(is);
} catch(IOException err) {
Log.e(err);
deleteStorageFile(filename);
}
}
int size = convertToPixels(imageSize);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
g.setAntiAliased(true);
g.setColor(0xffffff);
g.fillArc(0, 0, size, size, 0, 360);
Object mask = temp.createMask();
Style s = new Style();
s.setFgColor(0xc2c2c2);
s.setBgTransparency(255);
s.setBgColor(0xe9e9e9);
FontImage x = FontImage.createMaterial(
FontImage.MATERIAL_PERSON, s, size);
Image avatarImg = x.fill(size, size);
if(avatarImg instanceof FontImage) {
avatarImg = ((FontImage)avatarImg).toImage();
}
avatarImg = avatarImg.applyMask(mask);
User
We create a mask image, that's a white on black circle that we'll use to crop the image so it will appear circular
if(existsInStorage(filename)) {
try(InputStream is = createStorageInputStream(filename)) {
return Image.createImage(is);
} catch(IOException err) {
Log.e(err);
deleteStorageFile(filename);
}
}
int size = convertToPixels(imageSize);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
g.setAntiAliased(true);
g.setColor(0xffffff);
g.fillArc(0, 0, size, size, 0, 360);
Object mask = temp.createMask();
Style s = new Style();
s.setFgColor(0xc2c2c2);
s.setBgTransparency(255);
s.setBgColor(0xe9e9e9);
FontImage x = FontImage.createMaterial(
FontImage.MATERIAL_PERSON, s, size);
Image avatarImg = x.fill(size, size);
if(avatarImg instanceof FontImage) {
avatarImg = ((FontImage)avatarImg).toImage();
}
avatarImg = avatarImg.applyMask(mask);
User
We use the material design font image of a person to create an avatar placeholder image
Graphics g = temp.getGraphics();
g.setAntiAliased(true);
g.setColor(0xffffff);
g.fillArc(0, 0, size, size, 0, 360);
Object mask = temp.createMask();
Style s = new Style();
s.setFgColor(0xc2c2c2);
s.setBgTransparency(255);
s.setBgColor(0xe9e9e9);
FontImage x = FontImage.createMaterial(
FontImage.MATERIAL_PERSON, s, size);
Image avatarImg = x.fill(size, size);
if(avatarImg instanceof FontImage) {
avatarImg = ((FontImage)avatarImg).toImage();
}
avatarImg = avatarImg.applyMask(mask);
if(avatar.get() != null) {
return URLImage.createToStorage(
EncodedImage.createFromImage(avatarImg, false),
filename, avatar.get(),
URLImage.createMaskAdapter(temp));
}
return avatarImg;
}
}
User
Masking doesn't work with FontImage so we convert the FontImage to a regular image and mask it
Graphics g = temp.getGraphics();
g.setAntiAliased(true);
g.setColor(0xffffff);
g.fillArc(0, 0, size, size, 0, 360);
Object mask = temp.createMask();
Style s = new Style();
s.setFgColor(0xc2c2c2);
s.setBgTransparency(255);
s.setBgColor(0xe9e9e9);
FontImage x = FontImage.createMaterial(
FontImage.MATERIAL_PERSON, s, size);
Image avatarImg = x.fill(size, size);
if(avatarImg instanceof FontImage) {
avatarImg = ((FontImage)avatarImg).toImage();
}
avatarImg = avatarImg.applyMask(mask);
if(avatar.get() != null) {
return URLImage.createToStorage(
EncodedImage.createFromImage(avatarImg, false),
filename, avatar.get(),
URLImage.createMaskAdapter(temp));
}
return avatarImg;
}
}
User
If we have an avatar URL we fetch the data from the URL into a file and mask using the given image automatically.

This isn't trivial but isn't hard either it will produce the round avatar images we see in Facebook. But we aren't done yet...
Post
✦User
✦Date
✦Title
✦Content
✦Visibility
✦Styling
✦Comments
✦Likes
© Codename One 2017 all rights reserved
We need to the `Post` object for the newsfeed which lists "posts" on the wall. Again we can refer to the UI to decide on the content of this class:

* User - the person who wrote the post

* Date

* Title

* Content

* Visibility - is it public, friend only etc.

* Styling - we can configure the background image/color of the post

* Comments

* Likes

We'd also need an id for the post as before. Likes can't be a numeric count, since each user can only like once we need a list of users who liked a post.

Comments should be represented as a comment object as well, I'll get to that soon.
public class Post implements PropertyBusinessObject {
public final Property<String, Post> id = new Property<>("id");
public final Property<User, Post> user =
new Property<>("user", User.class);
public final LongProperty<Post> date = new LongProperty<>("date");
public final Property<String, Post> title = new Property<>("title");
public final Property<String, Post> content = new Property<>("content");
public final Property<String, Post> type = new Property<>("type");
public final Property<String, Post> visibility =
new Property<>("visibility");
public final Property<String, Post> styling = new Property<>("styling");
public final ListProperty<Comment, Post> comments =
new ListProperty<>("comment", Comment.class);
public final ListProperty<User, Post> likes =
new ListProperty<>("likes", User.class);
private final PropertyIndex idx = new PropertyIndex(this, "Post",
id, user, date, title, content, type, visibility, styling,
comments, likes);
@Override
public PropertyIndex getPropertyIndex() {
Post
This is the post class.

Again the class matches the UI almost to the letter
public class Post implements PropertyBusinessObject {
public final Property<String, Post> id = new Property<>("id");
public final Property<User, Post> user =
new Property<>("user", User.class);
public final LongProperty<Post> date = new LongProperty<>("date");
public final Property<String, Post> title = new Property<>("title");
public final Property<String, Post> content = new Property<>("content");
public final Property<String, Post> type = new Property<>("type");
public final Property<String, Post> visibility =
new Property<>("visibility");
public final Property<String, Post> styling = new Property<>("styling");
public final ListProperty<Comment, Post> comments =
new ListProperty<>("comment", Comment.class);
public final ListProperty<User, Post> likes =
new ListProperty<>("likes", User.class);
private final PropertyIndex idx = new PropertyIndex(this, "Post",
id, user, date, title, content, type, visibility, styling,
comments, likes);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
}
Post
Comments and likes use list property to handle multiple entries under a post
public class Comment implements PropertyBusinessObject {
public final Property<String, Comment> id = new Property<>("id");
public final Property<String, Comment> postId =
new Property<>("post");
public final Property<User, Comment> userId =
new Property<>("userId");
public final Property<String, Comment> parentComment =
new Property<>("parentComment");
public final LongProperty<Comment> date = new LongProperty<>("date");
public final Property<String, Comment> text = new Property<>("text");
private final PropertyIndex idx = new PropertyIndex(this, "Comment",
id, postId, userId, date, parentComment, text);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
}
Comment
This raises the obvious question about a comment, since we aren't close to implementing threaded comments yet I'll have to guess about the content of this entry.

Comments are bound to a parent post
public class Comment implements PropertyBusinessObject {
public final Property<String, Comment> id = new Property<>("id");
public final Property<String, Comment> postId =
new Property<>("post");
public final Property<User, Comment> userId =
new Property<>("userId");
public final Property<String, Comment> parentComment =
new Property<>("parentComment");
public final LongProperty<Comment> date = new LongProperty<>("date");
public final Property<String, Comment> text = new Property<>("text");
private final PropertyIndex idx = new PropertyIndex(this, "Comment",
id, postId, userId, date, parentComment, text);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
}
Comment
They can be posted by any user, notice I use ID's instead of objects. This will be simpler during parsing of the data
public class Comment implements PropertyBusinessObject {
public final Property<String, Comment> id = new Property<>("id");
public final Property<String, Comment> postId =
new Property<>("post");
public final Property<User, Comment> userId =
new Property<>("userId");
public final Property<String, Comment> parentComment =
new Property<>("parentComment");
public final LongProperty<Comment> date = new LongProperty<>("date");
public final Property<String, Comment> text = new Property<>("text");
private final PropertyIndex idx = new PropertyIndex(this, "Comment",
id, postId, userId, date, parentComment, text);
@Override
public PropertyIndex getPropertyIndex() {
return idx;
}
}
Comment
The id of the parent comment or null. This allows us to implement nested comment threads. 

We need one final piece in the data model for now...

More Related Content

Similar to Creating a Facebook Clone - Part X - Transcript.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
ShaiAlmog1
 
Creating an Uber Clone - Part X.pdf
Creating an Uber Clone - Part X.pdfCreating an Uber Clone - Part X.pdf
Creating an Uber Clone - Part X.pdf
ShaiAlmog1
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)
Remy Sharp
 
Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02
PL dream
 
Android workshop
Android workshopAndroid workshop
Android workshop
Michael Galpin
 
Struts 2 + Spring
Struts 2 + SpringStruts 2 + Spring
Struts 2 + Spring
Bryan Hsueh
 
Diving in the Flex Data Binding Waters
Diving in the Flex Data Binding WatersDiving in the Flex Data Binding Waters
Diving in the Flex Data Binding Waters
michael.labriola
 
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
ShaiAlmog1
 
Performance and Memory Tuning - Part VII.pdf
Performance and Memory Tuning - Part VII.pdfPerformance and Memory Tuning - Part VII.pdf
Performance and Memory Tuning - Part VII.pdf
ShaiAlmog1
 
Creating an Uber Clone - Part XXXX.pdf
Creating an Uber Clone - Part XXXX.pdfCreating an Uber Clone - Part XXXX.pdf
Creating an Uber Clone - Part XXXX.pdf
ShaiAlmog1
 
I am sorry but my major does not cover programming in depth (ICT) an.pdf
I am sorry but my major does not cover programming in depth (ICT) an.pdfI am sorry but my major does not cover programming in depth (ICT) an.pdf
I am sorry but my major does not cover programming in depth (ICT) an.pdf
seamusschwaabl99557
 
Academy PRO: React native - building first scenes
Academy PRO: React native - building first scenesAcademy PRO: React native - building first scenes
Academy PRO: React native - building first scenes
Binary Studio
 
2. Create a Java class called EmployeeMain within the same project Pr.docx
 2. Create a Java class called EmployeeMain within the same project Pr.docx 2. Create a Java class called EmployeeMain within the same project Pr.docx
2. Create a Java class called EmployeeMain within the same project Pr.docx
ajoy21
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
CodeFest
 
Polymer - pleasant client-side programming with web components
Polymer - pleasant client-side programming with web componentsPolymer - pleasant client-side programming with web components
Polymer - pleasant client-side programming with web components
psstoev
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
Julie Iskander
 
JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"
GeeksLab Odessa
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
Ryunosuke SATO
 
PyCon India 2010 Building Scalable apps using appengine
PyCon India 2010 Building Scalable apps using appenginePyCon India 2010 Building Scalable apps using appengine
PyCon India 2010 Building Scalable apps using appengine
Pranav Prakash
 
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
ShaiAlmog1
 

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

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 an Uber Clone - Part X.pdf
Creating an Uber Clone - Part X.pdfCreating an Uber Clone - Part X.pdf
Creating an Uber Clone - Part X.pdf
 
Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)Is HTML5 Ready? (workshop)
Is HTML5 Ready? (workshop)
 
Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02Is html5-ready-workshop-110727181512-phpapp02
Is html5-ready-workshop-110727181512-phpapp02
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Struts 2 + Spring
Struts 2 + SpringStruts 2 + Spring
Struts 2 + Spring
 
Diving in the Flex Data Binding Waters
Diving in the Flex Data Binding WatersDiving in the Flex Data Binding Waters
Diving in the Flex Data Binding Waters
 
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
 
Performance and Memory Tuning - Part VII.pdf
Performance and Memory Tuning - Part VII.pdfPerformance and Memory Tuning - Part VII.pdf
Performance and Memory Tuning - Part VII.pdf
 
Creating an Uber Clone - Part XXXX.pdf
Creating an Uber Clone - Part XXXX.pdfCreating an Uber Clone - Part XXXX.pdf
Creating an Uber Clone - Part XXXX.pdf
 
I am sorry but my major does not cover programming in depth (ICT) an.pdf
I am sorry but my major does not cover programming in depth (ICT) an.pdfI am sorry but my major does not cover programming in depth (ICT) an.pdf
I am sorry but my major does not cover programming in depth (ICT) an.pdf
 
Academy PRO: React native - building first scenes
Academy PRO: React native - building first scenesAcademy PRO: React native - building first scenes
Academy PRO: React native - building first scenes
 
2. Create a Java class called EmployeeMain within the same project Pr.docx
 2. Create a Java class called EmployeeMain within the same project Pr.docx 2. Create a Java class called EmployeeMain within the same project Pr.docx
2. Create a Java class called EmployeeMain within the same project Pr.docx
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
 
Polymer - pleasant client-side programming with web components
Polymer - pleasant client-side programming with web componentsPolymer - pleasant client-side programming with web components
Polymer - pleasant client-side programming with web components
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
 
JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
PyCon India 2010 Building Scalable apps using appengine
PyCon India 2010 Building Scalable apps using appenginePyCon India 2010 Building Scalable apps using appengine
PyCon India 2010 Building Scalable apps using appengine
 
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
 

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

RESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for studentsRESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for students
KAMESHS29
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
danishmna97
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
Pixlogix Infotech
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
DianaGray10
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy SurveyTrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
Neo4j
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
Zilliz
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
IndexBug
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
tolgahangng
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Malak Abu Hammad
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
Neo4j
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
innovationoecd
 

Recently uploaded (20)

RESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for studentsRESUME BUILDER APPLICATION Project for students
RESUME BUILDER APPLICATION Project for students
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
 
Best 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERPBest 20 SEO Techniques To Improve Website Visibility In SERP
Best 20 SEO Techniques To Improve Website Visibility In SERP
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy SurveyTrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy Survey
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
 
Programming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup SlidesProgramming Foundation Models with DSPy - Meetup Slides
Programming Foundation Models with DSPy - Meetup Slides
 
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceAI 101: An Introduction to the Basics and Impact of Artificial Intelligence
AI 101: An Introduction to the Basics and Impact of Artificial Intelligence
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Serial Arm Control in Real Time Presentation
Serial Arm Control in Real Time PresentationSerial Arm Control in Real Time Presentation
Serial Arm Control in Real Time Presentation
 
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
 
Presentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of GermanyPresentation of the OECD Artificial Intelligence Review of Germany
Presentation of the OECD Artificial Intelligence Review of Germany
 

Creating a Facebook Clone - Part X - Transcript.pdf

  • 1. Creating a Facebook Clone - Part X There is a fine line between doing a mockup and implementing a data model. Once we have a UI in place designing the underlying data model becomes a puzzle of filling in the missing pieces. Before we go into the newsfeed I'd like to create the objects that represent users and posts. Having these in place will make things easier when we want to implement the server.
  • 2. User ✦First Name ✦Family Name ✦Email ✦Phone ✦Gender ✦Birthday © Codename One 2017 all rights reserved We'll use property objects which make server communication & caching trivial. First we'll start with the User object. We will need a new package to separate the data model, I went with: com.codename1.fbclone.data. So what do we need for a user? A lot of these things are obvious from the signup UI: * First name * FamilyName * Email * Phone * Gender * Birthday
  • 3. public class User implements PropertyBusinessObject { public final Property<String, User> id = new Property<>("id"); public final Property<String, User> firstName = new Property<>("firstName"); public final Property<String, User> familyName = new Property<>("familyName"); public final Property<String, User> email = new Property<>("email"); public final Property<String, User> phone = new Property<>("phone"); public final Property<String, User> gender = new Property<>("gender"); public final LongProperty<User> birthday = new LongProperty<>("birthday"); public final Property<String, User> avatar = new Property<>("avatar"); private final PropertyIndex idx = new PropertyIndex(this, "User", id, firstName, familyName, email, phone, gender, avatar, birthday); @Override public PropertyIndex getPropertyIndex() { return idx; } public String fullName() { return firstName.get() + " " + familyName.get(); } User We also need a unique id, since security is crucial I will go with a string based unique id. We also need a picture of the user to show next to his posts so an avatar entry will also help. This is all easy to express in a business object class. These properties match the things we said we needed to know about a user
  • 4. public class User implements PropertyBusinessObject { public final Property<String, User> id = new Property<>("id"); public final Property<String, User> firstName = new Property<>("firstName"); public final Property<String, User> familyName = new Property<>("familyName"); public final Property<String, User> email = new Property<>("email"); public final Property<String, User> phone = new Property<>("phone"); public final Property<String, User> gender = new Property<>("gender"); public final LongProperty<User> birthday = new LongProperty<>("birthday"); public final Property<String, User> avatar = new Property<>("avatar"); private final PropertyIndex idx = new PropertyIndex(this, "User", id, firstName, familyName, email, phone, gender, avatar, birthday); @Override public PropertyIndex getPropertyIndex() { return idx; } public String fullName() { return firstName.get() + " " + familyName.get(); } User Dates are easy to store as long values since epoch
  • 5. new LongProperty<>("birthday"); public final Property<String, User> avatar = new Property<>("avatar"); private final PropertyIndex idx = new PropertyIndex(this, "User", id, firstName, familyName, email, phone, gender, avatar, birthday); @Override public PropertyIndex getPropertyIndex() { return idx; } public String fullName() { return firstName.get() + " " + familyName.get(); } public Image getAvatar(float imageSize) { String filename = "round-avatar-" + imageSize + "-" + id.get(); if(existsInStorage(filename)) { try(InputStream is = createStorageInputStream(filename);) { return Image.createImage(is); } catch(IOException err) { Log.e(err); deleteStorageFile(filename); } } int size = convertToPixels(imageSize); Image temp = Image.createImage(size, size, 0xff000000); Graphics g = temp.getGraphics(); User Getting the full name is a pretty common thing so it makes sense to provide this helper method.
  • 6. new LongProperty<>("birthday"); public final Property<String, User> avatar = new Property<>("avatar"); private final PropertyIndex idx = new PropertyIndex(this, "User", id, firstName, familyName, email, phone, gender, avatar, birthday); @Override public PropertyIndex getPropertyIndex() { return idx; } public String fullName() { return firstName.get() + " " + familyName.get(); } public Image getAvatar(float imageSize) { String filename = "round-avatar-" + imageSize + "-" + id.get(); if(existsInStorage(filename)) { try(InputStream is = createStorageInputStream(filename);) { return Image.createImage(is); } catch(IOException err) { Log.e(err); deleteStorageFile(filename); } } int size = convertToPixels(imageSize); Image temp = Image.createImage(size, size, 0xff000000); Graphics g = temp.getGraphics(); User Everything about this class is really simple except for the avatar. It should point at an image URL but how would we use it? To simplify that I'll add a getAvatar method to User that will include the functionality of fetching/caching/resizing and shaping the avatar image. The method accepts the image size in millimeters and returns an Image that matches that size
  • 7. new LongProperty<>("birthday"); public final Property<String, User> avatar = new Property<>("avatar"); private final PropertyIndex idx = new PropertyIndex(this, "User", id, firstName, familyName, email, phone, gender, avatar, birthday); @Override public PropertyIndex getPropertyIndex() { return idx; } public String fullName() { return firstName.get() + " " + familyName.get(); } public Image getAvatar(float imageSize) { String filename = "round-avatar-" + imageSize + "-" + id.get(); if(existsInStorage(filename)) { try(InputStream is = createStorageInputStream(filename)) { return Image.createImage(is); } catch(IOException err) { Log.e(err); deleteStorageFile(filename); } } int size = convertToPixels(imageSize); Image temp = Image.createImage(size, size, 0xff000000); Graphics g = temp.getGraphics(); User If we have an image in cache for this user we'll return that image
  • 8. new LongProperty<>("birthday"); public final Property<String, User> avatar = new Property<>("avatar"); private final PropertyIndex idx = new PropertyIndex(this, "User", id, firstName, familyName, email, phone, gender, avatar, birthday); @Override public PropertyIndex getPropertyIndex() { return idx; } public String fullName() { return firstName.get() + " " + familyName.get(); } public Image getAvatar(float imageSize) { String filename = "round-avatar-" + imageSize + "-" + id.get(); if(existsInStorage(filename)) { try(InputStream is = createStorageInputStream(filename)) { return Image.createImage(is); } catch(IOException err) { Log.e(err); deleteStorageFile(filename); } } int size = convertToPixels(imageSize); Image temp = Image.createImage(size, size, 0xff000000); Graphics g = temp.getGraphics(); User We load the image from storage, if loading failed due to corrupt image we'll delete the image file so the next call to this method will re-create it
  • 9. if(existsInStorage(filename)) { try(InputStream is = createStorageInputStream(filename)) { return Image.createImage(is); } catch(IOException err) { Log.e(err); deleteStorageFile(filename); } } int size = convertToPixels(imageSize); Image temp = Image.createImage(size, size, 0xff000000); Graphics g = temp.getGraphics(); g.setAntiAliased(true); g.setColor(0xffffff); g.fillArc(0, 0, size, size, 0, 360); Object mask = temp.createMask(); Style s = new Style(); s.setFgColor(0xc2c2c2); s.setBgTransparency(255); s.setBgColor(0xe9e9e9); FontImage x = FontImage.createMaterial( FontImage.MATERIAL_PERSON, s, size); Image avatarImg = x.fill(size, size); if(avatarImg instanceof FontImage) { avatarImg = ((FontImage)avatarImg).toImage(); } avatarImg = avatarImg.applyMask(mask); User We create a mask image, that's a white on black circle that we'll use to crop the image so it will appear circular
  • 10. if(existsInStorage(filename)) { try(InputStream is = createStorageInputStream(filename)) { return Image.createImage(is); } catch(IOException err) { Log.e(err); deleteStorageFile(filename); } } int size = convertToPixels(imageSize); Image temp = Image.createImage(size, size, 0xff000000); Graphics g = temp.getGraphics(); g.setAntiAliased(true); g.setColor(0xffffff); g.fillArc(0, 0, size, size, 0, 360); Object mask = temp.createMask(); Style s = new Style(); s.setFgColor(0xc2c2c2); s.setBgTransparency(255); s.setBgColor(0xe9e9e9); FontImage x = FontImage.createMaterial( FontImage.MATERIAL_PERSON, s, size); Image avatarImg = x.fill(size, size); if(avatarImg instanceof FontImage) { avatarImg = ((FontImage)avatarImg).toImage(); } avatarImg = avatarImg.applyMask(mask); User We use the material design font image of a person to create an avatar placeholder image
  • 11. Graphics g = temp.getGraphics(); g.setAntiAliased(true); g.setColor(0xffffff); g.fillArc(0, 0, size, size, 0, 360); Object mask = temp.createMask(); Style s = new Style(); s.setFgColor(0xc2c2c2); s.setBgTransparency(255); s.setBgColor(0xe9e9e9); FontImage x = FontImage.createMaterial( FontImage.MATERIAL_PERSON, s, size); Image avatarImg = x.fill(size, size); if(avatarImg instanceof FontImage) { avatarImg = ((FontImage)avatarImg).toImage(); } avatarImg = avatarImg.applyMask(mask); if(avatar.get() != null) { return URLImage.createToStorage( EncodedImage.createFromImage(avatarImg, false), filename, avatar.get(), URLImage.createMaskAdapter(temp)); } return avatarImg; } } User Masking doesn't work with FontImage so we convert the FontImage to a regular image and mask it
  • 12. Graphics g = temp.getGraphics(); g.setAntiAliased(true); g.setColor(0xffffff); g.fillArc(0, 0, size, size, 0, 360); Object mask = temp.createMask(); Style s = new Style(); s.setFgColor(0xc2c2c2); s.setBgTransparency(255); s.setBgColor(0xe9e9e9); FontImage x = FontImage.createMaterial( FontImage.MATERIAL_PERSON, s, size); Image avatarImg = x.fill(size, size); if(avatarImg instanceof FontImage) { avatarImg = ((FontImage)avatarImg).toImage(); } avatarImg = avatarImg.applyMask(mask); if(avatar.get() != null) { return URLImage.createToStorage( EncodedImage.createFromImage(avatarImg, false), filename, avatar.get(), URLImage.createMaskAdapter(temp)); } return avatarImg; } } User If we have an avatar URL we fetch the data from the URL into a file and mask using the given image automatically. This isn't trivial but isn't hard either it will produce the round avatar images we see in Facebook. But we aren't done yet...
  • 13. Post ✦User ✦Date ✦Title ✦Content ✦Visibility ✦Styling ✦Comments ✦Likes © Codename One 2017 all rights reserved We need to the `Post` object for the newsfeed which lists "posts" on the wall. Again we can refer to the UI to decide on the content of this class: * User - the person who wrote the post * Date * Title * Content * Visibility - is it public, friend only etc. * Styling - we can configure the background image/color of the post * Comments * Likes We'd also need an id for the post as before. Likes can't be a numeric count, since each user can only like once we need a list of users who liked a post. Comments should be represented as a comment object as well, I'll get to that soon.
  • 14. public class Post implements PropertyBusinessObject { public final Property<String, Post> id = new Property<>("id"); public final Property<User, Post> user = new Property<>("user", User.class); public final LongProperty<Post> date = new LongProperty<>("date"); public final Property<String, Post> title = new Property<>("title"); public final Property<String, Post> content = new Property<>("content"); public final Property<String, Post> type = new Property<>("type"); public final Property<String, Post> visibility = new Property<>("visibility"); public final Property<String, Post> styling = new Property<>("styling"); public final ListProperty<Comment, Post> comments = new ListProperty<>("comment", Comment.class); public final ListProperty<User, Post> likes = new ListProperty<>("likes", User.class); private final PropertyIndex idx = new PropertyIndex(this, "Post", id, user, date, title, content, type, visibility, styling, comments, likes); @Override public PropertyIndex getPropertyIndex() { Post This is the post class. Again the class matches the UI almost to the letter
  • 15. public class Post implements PropertyBusinessObject { public final Property<String, Post> id = new Property<>("id"); public final Property<User, Post> user = new Property<>("user", User.class); public final LongProperty<Post> date = new LongProperty<>("date"); public final Property<String, Post> title = new Property<>("title"); public final Property<String, Post> content = new Property<>("content"); public final Property<String, Post> type = new Property<>("type"); public final Property<String, Post> visibility = new Property<>("visibility"); public final Property<String, Post> styling = new Property<>("styling"); public final ListProperty<Comment, Post> comments = new ListProperty<>("comment", Comment.class); public final ListProperty<User, Post> likes = new ListProperty<>("likes", User.class); private final PropertyIndex idx = new PropertyIndex(this, "Post", id, user, date, title, content, type, visibility, styling, comments, likes); @Override public PropertyIndex getPropertyIndex() { return idx; } } Post Comments and likes use list property to handle multiple entries under a post
  • 16. public class Comment implements PropertyBusinessObject { public final Property<String, Comment> id = new Property<>("id"); public final Property<String, Comment> postId = new Property<>("post"); public final Property<User, Comment> userId = new Property<>("userId"); public final Property<String, Comment> parentComment = new Property<>("parentComment"); public final LongProperty<Comment> date = new LongProperty<>("date"); public final Property<String, Comment> text = new Property<>("text"); private final PropertyIndex idx = new PropertyIndex(this, "Comment", id, postId, userId, date, parentComment, text); @Override public PropertyIndex getPropertyIndex() { return idx; } } Comment This raises the obvious question about a comment, since we aren't close to implementing threaded comments yet I'll have to guess about the content of this entry. Comments are bound to a parent post
  • 17. public class Comment implements PropertyBusinessObject { public final Property<String, Comment> id = new Property<>("id"); public final Property<String, Comment> postId = new Property<>("post"); public final Property<User, Comment> userId = new Property<>("userId"); public final Property<String, Comment> parentComment = new Property<>("parentComment"); public final LongProperty<Comment> date = new LongProperty<>("date"); public final Property<String, Comment> text = new Property<>("text"); private final PropertyIndex idx = new PropertyIndex(this, "Comment", id, postId, userId, date, parentComment, text); @Override public PropertyIndex getPropertyIndex() { return idx; } } Comment They can be posted by any user, notice I use ID's instead of objects. This will be simpler during parsing of the data
  • 18. public class Comment implements PropertyBusinessObject { public final Property<String, Comment> id = new Property<>("id"); public final Property<String, Comment> postId = new Property<>("post"); public final Property<User, Comment> userId = new Property<>("userId"); public final Property<String, Comment> parentComment = new Property<>("parentComment"); public final LongProperty<Comment> date = new LongProperty<>("date"); public final Property<String, Comment> text = new Property<>("text"); private final PropertyIndex idx = new PropertyIndex(this, "Comment", id, postId, userId, date, parentComment, text); @Override public PropertyIndex getPropertyIndex() { return idx; } } Comment The id of the parent comment or null. This allows us to implement nested comment threads. We need one final piece in the data model for now...