SlideShare a Scribd company logo
1 of 41
Download to read offline
Creating an Uber Clone - Part III
In this part we’ll create a mockup for some of the forms starting with the login process
Country Button
© Codename One 2017 all rights reserved
We’ll start with the login form… Since the uber app is portrait locked it should be pretty easy to reproduce this UI. 

However, we’ll start first with one element and that’s the country button.
Country Button
© Codename One 2017 all rights reserved
The reason it’s logistically separate is that it has some non-trivial logic and resides in 2 separate forms. So it makes sense to define it in a single generic class
public class CountryCodePicker extends Button {
private Resources flagResource;
public CountryCodePicker() {
setUIID("CountryCodePicker");
addActionListener(e -> showPickerForm());
String code = L10NManager.getInstance().getLocale();
if(code != null) {
String[] countryCodes;
if(code.length() == 2) {
countryCodes = COUNTRY_ISO2;
} else {
if(code.length() == 3) {
countryCodes = COUNTRY_ISO3;
} else {
return;
}
}
code = code.toUpperCase();
try {
flagResource = Resources.open("/flags.res");
} catch(IOException err) {
CountryCodePicker
The country code picker is a button subclass but it doesn’t really look like it
public class CountryCodePicker extends Button {
private Resources flagResource;
public CountryCodePicker() {
setUIID("CountryCodePicker");
addActionListener(e -> showPickerForm());
String code = L10NManager.getInstance().getLocale();
if(code != null) {
String[] countryCodes;
if(code.length() == 2) {
countryCodes = COUNTRY_ISO2;
} else {
if(code.length() == 3) {
countryCodes = COUNTRY_ISO3;
} else {
return;
}
}
code = code.toUpperCase();
try {
flagResource = Resources.open("/flags.res");
} catch(IOException err) {
CountryCodePicker
Because we set the UIID to the CountryCodePicker UIID
public class CountryCodePicker extends Button {
private Resources flagResource;
public CountryCodePicker() {
setUIID("CountryCodePicker");
addActionListener(e -> showPickerForm());
String code = L10NManager.getInstance().getLocale();
if(code != null) {
String[] countryCodes;
if(code.length() == 2) {
countryCodes = COUNTRY_ISO2;
} else {
if(code.length() == 3) {
countryCodes = COUNTRY_ISO3;
} else {
return;
}
}
code = code.toUpperCase();
try {
flagResource = Resources.open("/flags.res");
} catch(IOException err) {
CountryCodePicker
In this block of code we try to "guess" the current country based on the localization settings
public class CountryCodePicker extends Button {
private Resources flagResource;
public CountryCodePicker() {
setUIID("CountryCodePicker");
addActionListener(e -> showPickerForm());
String code = L10NManager.getInstance().getLocale();
if(code != null) {
String[] countryCodes;
if(code.length() == 2) {
countryCodes = COUNTRY_ISO2;
} else {
if(code.length() == 3) {
countryCodes = COUNTRY_ISO3;
} else {
return;
}
}
code = code.toUpperCase();
try {
flagResource = Resources.open("/flags.res");
} catch(IOException err) {
CountryCodePicker
The flags.res file is included in the SMSActivation cn1lib. It's a bit of an implementation detail so this code might break in the future if so we might need to copy the res
file from there or update the code.
try {
flagResource = Resources.open("/flags.res");
} catch(IOException err) {
Log.e(err);
}
Image blankIcon = Image.createImage(100, 70, 0);
for(int iter = 0 ; iter < countryCodes.length ; iter++) {
if(code.equals(countryCodes[iter])) {
setText("+" + COUNTRY_CODES[iter]);
setIcon(flagResource.getImage(COUNTRY_FLAGS[iter]));
if(getIcon() == null) {
setIcon(blankIcon);
}
return;
}
}
}
}
protected void showPickerForm() {
final Form f = getCurrentForm();
final Transition t = f.getTransitionOutAnimator();
CountryCodePicker
We don't have all the flags for all the countries. Without a blank icon the alignment might seem “broken" so it’s crucial to have this
setIcon(blankIcon);
}
return;
}
}
}
}
protected void showPickerForm() {
final Form f = getCurrentForm();
final Transition t = f.getTransitionOutAnimator();
f.setTransitionOutAnimator(CommonTransitions.createEmpty());
Form tf = new CountryPickerForm(this, flagResource);
tf.addShowListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
f.setTransitionOutAnimator(t);
f.removeShowListener(this);
}
});
tf.show();
}
CountryCodePicker
showPickerForm is useful for overriding. In the login form clicking this button should lead to a different form. However there is a lot more going on here…

The cover transition collides with the default slide transition producing a weird effect. So here we keep the transition instance. Remove the out transition so the cover
effect will work properly. We then bind a show listener that restores the old transition after we are done. That's important for when the user will click to move to the next
form..
CountryCodePicker
© Codename One 2017 all rights reserved
The styling for country code picker are pretty simple. It’s black on transparent background.
CountryCodePicker
© Codename One 2017 all rights reserved
The padding is Big on the left but small on the right so the text element stays near the button
CountryCodePicker
© Codename One 2017 all rights reserved
Margin again is 0
CountryCodePicker
© Codename One 2017 all rights reserved
And the font is a pretty standard light 3 millimeter font
public class LoginForm extends Form {
public LoginForm() {
super(new BorderLayout());
Label squareLogo = new Label("",
Resources.getGlobalResources().getImage("uber-logo.png"),
"SquareLogo") {
@Override
protected Dimension calcPreferredSize() {
Dimension size = super.calcPreferredSize();
size.setHeight(size.getWidth());
return size;
}
};
Container logo = BorderLayout.centerAbsolute(squareLogo);
logo.setUIID("LogoBackground");
add(CENTER, logo);
Label getMovingWithUber = new Label("Get moving with Uber", "GetMovingWithUber");
CountryCodePicker countryCodeButton = new CountryCodePicker() {
@Override
LoginForm
So without further ado, lets go to the login form code. This is the code of the first form you see when the Uber app launches. It’s a relatively simple class without too
many frills. Lets go over a few elements of note.

Initially I wrote the word `UBER`. Without the right font it looked "weird". Using an image for a logo is generally the best approach
public class LoginForm extends Form {
public LoginForm() {
super(new BorderLayout());
Label squareLogo = new Label("",
Resources.getGlobalResources().getImage("uber-logo.png"),
"SquareLogo") {
@Override
protected Dimension calcPreferredSize() {
Dimension size = super.calcPreferredSize();
size.setHeight(size.getWidth());
return size;
}
};
Container logo = BorderLayout.centerAbsolute(squareLogo);
logo.setUIID("LogoBackground");
add(CENTER, logo);
Label getMovingWithUber = new Label("Get moving with Uber", "GetMovingWithUber");
CountryCodePicker countryCodeButton = new CountryCodePicker() {
@Override
LoginForm
I want the logo to be square so height and width would be identical
public class LoginForm extends Form {
public LoginForm() {
super(new BorderLayout());
Label squareLogo = new Label("",
Resources.getGlobalResources().getImage("uber-logo.png"),
"SquareLogo") {
@Override
protected Dimension calcPreferredSize() {
Dimension size = super.calcPreferredSize();
size.setHeight(size.getWidth());
return size;
}
};
Container logo = BorderLayout.centerAbsolute(squareLogo);
logo.setUIID("LogoBackground");
add(CENTER, logo);
Label getMovingWithUber = new Label("Get moving with Uber", "GetMovingWithUber");
CountryCodePicker countryCodeButton = new CountryCodePicker() {
@Override
LoginForm
We place the entire tiled section and logo in the center of the form so they will take up the available space. We place the logo itself in the absolute center so it will float in
the middle
CountryCodePicker countryCodeButton = new CountryCodePicker() {
@Override
protected void showPickerForm() {
new EnterMobileNumberForm().show();
}
};
SpanButton phoneNumber = new SpanButton("Enter your mobile number",
"PhoneNumberHint");
phoneNumber.getTextComponent().setColumns(80);
phoneNumber.getTextComponent().setRows(2);
phoneNumber.getTextComponent().setGrowByContent(false);
phoneNumber.setUIID("Container");
phoneNumber.addActionListener(e -> new EnterMobileNumberForm().show());
Container phonePicking = BorderLayout.centerCenterEastWest(
phoneNumber,
null, countryCodeButton);
phonePicking.setUIID("Separator");
Button social = new Button("Or connect with social", "ConnectWithSocialButton");
social.addActionListener(e -> new FacebookOrGoogleLoginForm().show());
LoginForm
I override the behavior of the country picker button for consistency with the native Uber app
CountryCodePicker countryCodeButton = new CountryCodePicker() {
@Override
protected void showPickerForm() {
new EnterMobileNumberForm().show();
}
};
SpanButton phoneNumber = new SpanButton("Enter your mobile number",
"PhoneNumberHint");
phoneNumber.getTextComponent().setColumns(80);
phoneNumber.getTextComponent().setRows(2);
phoneNumber.getTextComponent().setGrowByContent(false);
phoneNumber.setUIID("Container");
phoneNumber.addActionListener(e -> new EnterMobileNumberForm().show());
Container phonePicking = BorderLayout.centerCenterEastWest(
phoneNumber,
null, countryCodeButton);
phonePicking.setUIID("Separator");
Button social = new Button("Or connect with social", "ConnectWithSocialButton");
social.addActionListener(e -> new FacebookOrGoogleLoginForm().show());
LoginForm
This looks like a text field but acts like a button in the naive app so I implemented it as such. Constraining the rows and size is important for proper layout
phoneNumber.addActionListener(e -> new EnterMobileNumberForm().show());
Container phonePicking = BorderLayout.centerCenterEastWest(
phoneNumber,
null, countryCodeButton);
phonePicking.setUIID("Separator");
Button social = new Button("Or connect with social", "ConnectWithSocialButton");
social.addActionListener(e -> new FacebookOrGoogleLoginForm().show());
add(SOUTH, BoxLayout.encloseY(getMovingWithUber, phonePicking, social));
}
@Override
protected boolean shouldPaintStatusBar() {
return false;
}
@Override
protected void initGlobalToolbar() {
}
}
LoginForm
The rest of the UI is relegated to the SOUTH of the form, this would have issues in landscape mode but since the app is portrait locked this shouldn't be a problem
Tile & Logo
© Codename One 2017 all rights reserved
We need these two images to complete the form UI, the tile.png and uber-logo.png
Square Logo
© Codename One 2017 all rights reserved
There are a few styles we need to define in order to finish this form. The square logo UIID is used for the logo. I still have the foreground defined as this used to be text
and not an image. The main things here are the white opaque background
Square Logo
© Codename One 2017 all rights reserved
We use some white padding on the logo
Square Logo
© Codename One 2017 all rights reserved
But we don’t need margin
LogoBackground
© Codename One 2017 all rights reserved
The logo background style represents the patterned tile in behind the logo… This is pretty easy to accomplish once we have the tile.png file we can style it to tile on both
axis
LogoBackground
© Codename One 2017 all rights reserved
We set the transparency to 255 as the image is opaque and we want to make sure this is totally opauqe
LogoBackground
© Codename One 2017 all rights reserved
We define the margin to 0 as usual. Notice we ignore padding as it just doesn’t matter for this component
GetMovingWithUber
© Codename One 2017 all rights reserved
The GetMovingWithUber UIID just sets the padding to a right size so it’s spaced enough from the sides but close enough to the element below
GetMovingWithUber
© Codename One 2017 all rights reserved
We don’t need margin, color or anything else because we derive from Label
GetMovingWithUber
© Codename One 2017 all rights reserved
The main reason for this UIID is the large dominating 4.8 millimeter font size
PhoneNumberHint
© Codename One 2017 all rights reserved
The phone number hint represents the text that looks like a hint next to the flag. When we move to the next form it actually becomes the real hint text. It’s gray with no
background
PhoneNumberHint
© Codename One 2017 all rights reserved
It has 0 padding on the left to keep it close to the country picker button
PhoneNumberHint
© Codename One 2017 all rights reserved
The font is 3.7 millimeters which looked right after some trial and error
Separator
© Codename One 2017 all rights reserved
The separator UIID is a container which has an underline below it. As a container we define it as completely transparent
Separator
© Codename One 2017 all rights reserved
It has a 2 pixel bottom padding to leave space for the underline
Separator
© Codename One 2017 all rights reserved
The margin is 0 as usual
Separator
© Codename One 2017 all rights reserved
The border is an underline 2 pixel border in a gray color
ConnectWithSocialButton
© Codename One 2017 all rights reserved
The ConnectWithSocialButton is the button at the bottom of the UI it looks like a label but has a bluish color
ConnectWithSocialButton
© Codename One 2017 all rights reserved
I need to define the padding even though it should be derived from label as deriving from builtin types isn’t always 100% reliable. I could have worked around it by
defining a MyLabel UIID and deriving from that.
ConnectWithSocialButton
© Codename One 2017 all rights reserved
I still chose to derive from Label which mostly works
ConnectWithSocialButton
© Codename One 2017 all rights reserved
But I defined the font just to be on the safe side…
The Login Form
© Codename One 2017 all rights reserved
This is the UI we’ve made next to the native Uber UI. You will notice some minor differences mostly with fonts not being pixel perfect. I didn’t aim for perfection with fonts
as that can be endless… There are some other nuances I’ll go into

More Related Content

Similar to Creating an Uber Clone - Part III - Transcript.pdf

Building Your First App with MongoDB Stitch
Building Your First App with MongoDB StitchBuilding Your First App with MongoDB Stitch
Building Your First App with MongoDB StitchMongoDB
 
Java Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdfJava Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdfSudhanshiBakre1
 
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...Andrey Karpov
 
Opensource gis development - part 3
Opensource gis development - part 3Opensource gis development - part 3
Opensource gis development - part 3Andrea Antonello
 
Tutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB StitchTutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB StitchMongoDB
 
The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196Mahmoud Samir Fayed
 
How data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesHow data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesElectronic Arts / DICE
 
android level 3
android level 3android level 3
android level 3DevMix
 
How to Create Custom Shaders in Flutter?
How to Create Custom Shaders in Flutter?How to Create Custom Shaders in Flutter?
How to Create Custom Shaders in Flutter?Flutter Agency
 
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docxbbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docxikirkton
 
Creating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfCreating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfShaiAlmog1
 
Recoil at Codete Webinars #3
Recoil at Codete Webinars #3Recoil at Codete Webinars #3
Recoil at Codete Webinars #3Mateusz Bryła
 
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...Ted Chien
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsAdégòkè Obasá
 
Style vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOSStyle vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOSKeith Norman
 

Similar to Creating an Uber Clone - Part III - Transcript.pdf (20)

Building Your First App with MongoDB Stitch
Building Your First App with MongoDB StitchBuilding Your First App with MongoDB Stitch
Building Your First App with MongoDB Stitch
 
Java Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdfJava Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdf
 
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerC...
 
Opensource gis development - part 3
Opensource gis development - part 3Opensource gis development - part 3
Opensource gis development - part 3
 
Who moved my pixels?!
Who moved my pixels?!Who moved my pixels?!
Who moved my pixels?!
 
Oops presentation
Oops presentationOops presentation
Oops presentation
 
Tutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB StitchTutorial: Building Your First App with MongoDB Stitch
Tutorial: Building Your First App with MongoDB Stitch
 
The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196The Ring programming language version 1.7 book - Part 87 of 196
The Ring programming language version 1.7 book - Part 87 of 196
 
How data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield HeroesHow data rules the world: Telemetry in Battlefield Heroes
How data rules the world: Telemetry in Battlefield Heroes
 
Dartprogramming
DartprogrammingDartprogramming
Dartprogramming
 
android level 3
android level 3android level 3
android level 3
 
CGI.ppt
CGI.pptCGI.ppt
CGI.ppt
 
How to Create Custom Shaders in Flutter?
How to Create Custom Shaders in Flutter?How to Create Custom Shaders in Flutter?
How to Create Custom Shaders in Flutter?
 
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docxbbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
bbyopenApp_Code.DS_StorebbyopenApp_CodeVBCodeGoogleMaps.docx
 
Creating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdfCreating an Uber Clone - Part IV - Transcript.pdf
Creating an Uber Clone - Part IV - Transcript.pdf
 
Recoil at Codete Webinars #3
Recoil at Codete Webinars #3Recoil at Codete Webinars #3
Recoil at Codete Webinars #3
 
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
viWave Study Group - Introduction to Google Android Development - Chapter 23 ...
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web Apps
 
Style vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOSStyle vs. Content and Clean Theming in iOS
Style vs. Content and Clean Theming in iOS
 
Html5 Overview
Html5 OverviewHtml5 Overview
Html5 Overview
 

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

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
 
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
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
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
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 

Recently uploaded (20)

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
 
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
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
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
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 

Creating an Uber Clone - Part III - Transcript.pdf

  • 1. Creating an Uber Clone - Part III In this part we’ll create a mockup for some of the forms starting with the login process
  • 2. Country Button © Codename One 2017 all rights reserved We’ll start with the login form… Since the uber app is portrait locked it should be pretty easy to reproduce this UI. However, we’ll start first with one element and that’s the country button.
  • 3. Country Button © Codename One 2017 all rights reserved The reason it’s logistically separate is that it has some non-trivial logic and resides in 2 separate forms. So it makes sense to define it in a single generic class
  • 4. public class CountryCodePicker extends Button { private Resources flagResource; public CountryCodePicker() { setUIID("CountryCodePicker"); addActionListener(e -> showPickerForm()); String code = L10NManager.getInstance().getLocale(); if(code != null) { String[] countryCodes; if(code.length() == 2) { countryCodes = COUNTRY_ISO2; } else { if(code.length() == 3) { countryCodes = COUNTRY_ISO3; } else { return; } } code = code.toUpperCase(); try { flagResource = Resources.open("/flags.res"); } catch(IOException err) { CountryCodePicker The country code picker is a button subclass but it doesn’t really look like it
  • 5. public class CountryCodePicker extends Button { private Resources flagResource; public CountryCodePicker() { setUIID("CountryCodePicker"); addActionListener(e -> showPickerForm()); String code = L10NManager.getInstance().getLocale(); if(code != null) { String[] countryCodes; if(code.length() == 2) { countryCodes = COUNTRY_ISO2; } else { if(code.length() == 3) { countryCodes = COUNTRY_ISO3; } else { return; } } code = code.toUpperCase(); try { flagResource = Resources.open("/flags.res"); } catch(IOException err) { CountryCodePicker Because we set the UIID to the CountryCodePicker UIID
  • 6. public class CountryCodePicker extends Button { private Resources flagResource; public CountryCodePicker() { setUIID("CountryCodePicker"); addActionListener(e -> showPickerForm()); String code = L10NManager.getInstance().getLocale(); if(code != null) { String[] countryCodes; if(code.length() == 2) { countryCodes = COUNTRY_ISO2; } else { if(code.length() == 3) { countryCodes = COUNTRY_ISO3; } else { return; } } code = code.toUpperCase(); try { flagResource = Resources.open("/flags.res"); } catch(IOException err) { CountryCodePicker In this block of code we try to "guess" the current country based on the localization settings
  • 7. public class CountryCodePicker extends Button { private Resources flagResource; public CountryCodePicker() { setUIID("CountryCodePicker"); addActionListener(e -> showPickerForm()); String code = L10NManager.getInstance().getLocale(); if(code != null) { String[] countryCodes; if(code.length() == 2) { countryCodes = COUNTRY_ISO2; } else { if(code.length() == 3) { countryCodes = COUNTRY_ISO3; } else { return; } } code = code.toUpperCase(); try { flagResource = Resources.open("/flags.res"); } catch(IOException err) { CountryCodePicker The flags.res file is included in the SMSActivation cn1lib. It's a bit of an implementation detail so this code might break in the future if so we might need to copy the res file from there or update the code.
  • 8. try { flagResource = Resources.open("/flags.res"); } catch(IOException err) { Log.e(err); } Image blankIcon = Image.createImage(100, 70, 0); for(int iter = 0 ; iter < countryCodes.length ; iter++) { if(code.equals(countryCodes[iter])) { setText("+" + COUNTRY_CODES[iter]); setIcon(flagResource.getImage(COUNTRY_FLAGS[iter])); if(getIcon() == null) { setIcon(blankIcon); } return; } } } } protected void showPickerForm() { final Form f = getCurrentForm(); final Transition t = f.getTransitionOutAnimator(); CountryCodePicker We don't have all the flags for all the countries. Without a blank icon the alignment might seem “broken" so it’s crucial to have this
  • 9. setIcon(blankIcon); } return; } } } } protected void showPickerForm() { final Form f = getCurrentForm(); final Transition t = f.getTransitionOutAnimator(); f.setTransitionOutAnimator(CommonTransitions.createEmpty()); Form tf = new CountryPickerForm(this, flagResource); tf.addShowListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { f.setTransitionOutAnimator(t); f.removeShowListener(this); } }); tf.show(); } CountryCodePicker showPickerForm is useful for overriding. In the login form clicking this button should lead to a different form. However there is a lot more going on here… The cover transition collides with the default slide transition producing a weird effect. So here we keep the transition instance. Remove the out transition so the cover effect will work properly. We then bind a show listener that restores the old transition after we are done. That's important for when the user will click to move to the next form..
  • 10. CountryCodePicker © Codename One 2017 all rights reserved The styling for country code picker are pretty simple. It’s black on transparent background.
  • 11. CountryCodePicker © Codename One 2017 all rights reserved The padding is Big on the left but small on the right so the text element stays near the button
  • 12. CountryCodePicker © Codename One 2017 all rights reserved Margin again is 0
  • 13. CountryCodePicker © Codename One 2017 all rights reserved And the font is a pretty standard light 3 millimeter font
  • 14. public class LoginForm extends Form { public LoginForm() { super(new BorderLayout()); Label squareLogo = new Label("", Resources.getGlobalResources().getImage("uber-logo.png"), "SquareLogo") { @Override protected Dimension calcPreferredSize() { Dimension size = super.calcPreferredSize(); size.setHeight(size.getWidth()); return size; } }; Container logo = BorderLayout.centerAbsolute(squareLogo); logo.setUIID("LogoBackground"); add(CENTER, logo); Label getMovingWithUber = new Label("Get moving with Uber", "GetMovingWithUber"); CountryCodePicker countryCodeButton = new CountryCodePicker() { @Override LoginForm So without further ado, lets go to the login form code. This is the code of the first form you see when the Uber app launches. It’s a relatively simple class without too many frills. Lets go over a few elements of note. Initially I wrote the word `UBER`. Without the right font it looked "weird". Using an image for a logo is generally the best approach
  • 15. public class LoginForm extends Form { public LoginForm() { super(new BorderLayout()); Label squareLogo = new Label("", Resources.getGlobalResources().getImage("uber-logo.png"), "SquareLogo") { @Override protected Dimension calcPreferredSize() { Dimension size = super.calcPreferredSize(); size.setHeight(size.getWidth()); return size; } }; Container logo = BorderLayout.centerAbsolute(squareLogo); logo.setUIID("LogoBackground"); add(CENTER, logo); Label getMovingWithUber = new Label("Get moving with Uber", "GetMovingWithUber"); CountryCodePicker countryCodeButton = new CountryCodePicker() { @Override LoginForm I want the logo to be square so height and width would be identical
  • 16. public class LoginForm extends Form { public LoginForm() { super(new BorderLayout()); Label squareLogo = new Label("", Resources.getGlobalResources().getImage("uber-logo.png"), "SquareLogo") { @Override protected Dimension calcPreferredSize() { Dimension size = super.calcPreferredSize(); size.setHeight(size.getWidth()); return size; } }; Container logo = BorderLayout.centerAbsolute(squareLogo); logo.setUIID("LogoBackground"); add(CENTER, logo); Label getMovingWithUber = new Label("Get moving with Uber", "GetMovingWithUber"); CountryCodePicker countryCodeButton = new CountryCodePicker() { @Override LoginForm We place the entire tiled section and logo in the center of the form so they will take up the available space. We place the logo itself in the absolute center so it will float in the middle
  • 17. CountryCodePicker countryCodeButton = new CountryCodePicker() { @Override protected void showPickerForm() { new EnterMobileNumberForm().show(); } }; SpanButton phoneNumber = new SpanButton("Enter your mobile number", "PhoneNumberHint"); phoneNumber.getTextComponent().setColumns(80); phoneNumber.getTextComponent().setRows(2); phoneNumber.getTextComponent().setGrowByContent(false); phoneNumber.setUIID("Container"); phoneNumber.addActionListener(e -> new EnterMobileNumberForm().show()); Container phonePicking = BorderLayout.centerCenterEastWest( phoneNumber, null, countryCodeButton); phonePicking.setUIID("Separator"); Button social = new Button("Or connect with social", "ConnectWithSocialButton"); social.addActionListener(e -> new FacebookOrGoogleLoginForm().show()); LoginForm I override the behavior of the country picker button for consistency with the native Uber app
  • 18. CountryCodePicker countryCodeButton = new CountryCodePicker() { @Override protected void showPickerForm() { new EnterMobileNumberForm().show(); } }; SpanButton phoneNumber = new SpanButton("Enter your mobile number", "PhoneNumberHint"); phoneNumber.getTextComponent().setColumns(80); phoneNumber.getTextComponent().setRows(2); phoneNumber.getTextComponent().setGrowByContent(false); phoneNumber.setUIID("Container"); phoneNumber.addActionListener(e -> new EnterMobileNumberForm().show()); Container phonePicking = BorderLayout.centerCenterEastWest( phoneNumber, null, countryCodeButton); phonePicking.setUIID("Separator"); Button social = new Button("Or connect with social", "ConnectWithSocialButton"); social.addActionListener(e -> new FacebookOrGoogleLoginForm().show()); LoginForm This looks like a text field but acts like a button in the naive app so I implemented it as such. Constraining the rows and size is important for proper layout
  • 19. phoneNumber.addActionListener(e -> new EnterMobileNumberForm().show()); Container phonePicking = BorderLayout.centerCenterEastWest( phoneNumber, null, countryCodeButton); phonePicking.setUIID("Separator"); Button social = new Button("Or connect with social", "ConnectWithSocialButton"); social.addActionListener(e -> new FacebookOrGoogleLoginForm().show()); add(SOUTH, BoxLayout.encloseY(getMovingWithUber, phonePicking, social)); } @Override protected boolean shouldPaintStatusBar() { return false; } @Override protected void initGlobalToolbar() { } } LoginForm The rest of the UI is relegated to the SOUTH of the form, this would have issues in landscape mode but since the app is portrait locked this shouldn't be a problem
  • 20. Tile & Logo © Codename One 2017 all rights reserved We need these two images to complete the form UI, the tile.png and uber-logo.png
  • 21. Square Logo © Codename One 2017 all rights reserved There are a few styles we need to define in order to finish this form. The square logo UIID is used for the logo. I still have the foreground defined as this used to be text and not an image. The main things here are the white opaque background
  • 22. Square Logo © Codename One 2017 all rights reserved We use some white padding on the logo
  • 23. Square Logo © Codename One 2017 all rights reserved But we don’t need margin
  • 24. LogoBackground © Codename One 2017 all rights reserved The logo background style represents the patterned tile in behind the logo… This is pretty easy to accomplish once we have the tile.png file we can style it to tile on both axis
  • 25. LogoBackground © Codename One 2017 all rights reserved We set the transparency to 255 as the image is opaque and we want to make sure this is totally opauqe
  • 26. LogoBackground © Codename One 2017 all rights reserved We define the margin to 0 as usual. Notice we ignore padding as it just doesn’t matter for this component
  • 27. GetMovingWithUber © Codename One 2017 all rights reserved The GetMovingWithUber UIID just sets the padding to a right size so it’s spaced enough from the sides but close enough to the element below
  • 28. GetMovingWithUber © Codename One 2017 all rights reserved We don’t need margin, color or anything else because we derive from Label
  • 29. GetMovingWithUber © Codename One 2017 all rights reserved The main reason for this UIID is the large dominating 4.8 millimeter font size
  • 30. PhoneNumberHint © Codename One 2017 all rights reserved The phone number hint represents the text that looks like a hint next to the flag. When we move to the next form it actually becomes the real hint text. It’s gray with no background
  • 31. PhoneNumberHint © Codename One 2017 all rights reserved It has 0 padding on the left to keep it close to the country picker button
  • 32. PhoneNumberHint © Codename One 2017 all rights reserved The font is 3.7 millimeters which looked right after some trial and error
  • 33. Separator © Codename One 2017 all rights reserved The separator UIID is a container which has an underline below it. As a container we define it as completely transparent
  • 34. Separator © Codename One 2017 all rights reserved It has a 2 pixel bottom padding to leave space for the underline
  • 35. Separator © Codename One 2017 all rights reserved The margin is 0 as usual
  • 36. Separator © Codename One 2017 all rights reserved The border is an underline 2 pixel border in a gray color
  • 37. ConnectWithSocialButton © Codename One 2017 all rights reserved The ConnectWithSocialButton is the button at the bottom of the UI it looks like a label but has a bluish color
  • 38. ConnectWithSocialButton © Codename One 2017 all rights reserved I need to define the padding even though it should be derived from label as deriving from builtin types isn’t always 100% reliable. I could have worked around it by defining a MyLabel UIID and deriving from that.
  • 39. ConnectWithSocialButton © Codename One 2017 all rights reserved I still chose to derive from Label which mostly works
  • 40. ConnectWithSocialButton © Codename One 2017 all rights reserved But I defined the font just to be on the safe side…
  • 41. The Login Form © Codename One 2017 all rights reserved This is the UI we’ve made next to the native Uber UI. You will notice some minor differences mostly with fonts not being pixel perfect. I didn’t aim for perfection with fonts as that can be endless… There are some other nuances I’ll go into