SlideShare a Scribd company logo
1 of 18
Download to read offline
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.pdfShaiAlmog1
 
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.pdfShaiAlmog1
 
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-phpapp02PL dream
 
Struts 2 + Spring
Struts 2 + SpringStruts 2 + Spring
Struts 2 + SpringBryan 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 Watersmichael.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.pdfShaiAlmog1
 
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.pdfShaiAlmog1
 
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.pdfShaiAlmog1
 
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.pdfseamusschwaabl99557
 
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 scenesBinary 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.docxajoy21
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr TolstykhCodeFest
 
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 componentspsstoev
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScriptJulie Iskander
 
JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"GeeksLab Odessa
 
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 appenginePranav 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.pdfShaiAlmog1
 

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.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

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 

Recently uploaded (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 

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...