SlideShare a Scribd company logo
1 of 11
Download to read offline
Miscellaneous Features - Part I
In this section we’ll cover a lot of minor features mostly related to UI that are part of the missing pieces on the road to complete the app
Categories
✦We first need to load the categories which we do in
the dish list form together with the dish loop
© Codename One 2017 all rights reserved
Menu menu = Restaurant.getInstance().menu.get();
if(menu.dishes.size() == 0) {
for(PropertyBusinessObject d : AppStorage.getInstance().fetchDishes()) {
Dish dsh = (Dish)d;
menu.dishes.add(dsh);
if(!menu.categories.asList().contains(dsh.category.get())) {
menu.categories.add(dsh.category.get());
}
}
}
Let’s start with the categories that we can see at the top of the restaurant application. When we fetch a dish we can check if a category is already added and if not we
can just add it into the list of categories.

This list is used later on when we build the list model for the categories.
Adding/Setting a Category
✦In the dish edit form we can set the category with a
completion list
© Codename One 2017 all rights reserved
String[] cats = new String[Restaurant.getInstance().menu.get().categories.size()];
Restaurant.getInstance().menu.get().categories.asList().toArray(cats);
AutoCompleteTextField category = new AutoCompleteTextField(cats);
if(!Restaurant.getInstance().menu.get().categories.asList().contains(category.getText())) {
Restaurant.getInstance().menu.get().categories.add(category.getText());
}
d.category.set(category.getText());
✦When we handle the OK event we can just add the
category automatically if it’s missing
In the dish edit form we can provide an auto complete text field which allows us to type in a new category or select an existing category.

In that same form when a user presses OK we check if the category already exists and if not we add it to the category list. This makes the whole process automatic and
effectively removes the Edit/Add/Delete UI for the categories list. That simplifies our work by removing forms we would have built and also simplifies the user experience.
Laziness pays off…
CategoryEntity ce = null;
for(CategoryEntity current : e.getCategories()) {
if(current.getName().equals(d.getCategory())) {
ce = current;
break;
}
}
if(ce == null && d.getCategory() != null) {
ce = new CategoryEntity(d.getCategory());
categoryRepository.save(ce);
}
CategoryEntity oe = de.getCategory();
de.setCategory(ce);
dishRepository.save(de);
if(d.getId() == null) {
Set<DishEntity> dishes = new HashSet<>(e.getDishes());
dishes.add(de);
e.setDishes(dishes);
restaurantRepository.save(e);
}
if(oe != null) {
cullCategory(e, oe);
}
Server - DishService Put Dish
Here we can see the server code for the categories and you will notice that it is handled as part of the dish update. There is no separate webservice for categories further
simplifying this logic.

We implicitly create a category if it’s missing and save it to the mysql database. We have a separate call to cull the category which we’ll go into now
private void cullCategory(RestaurantEntity e, CategoryEntity ce) {
for(DishEntity de : e.getDishes()) {
if(ce.equals(de.getCategory())) {
return;
}
}
categoryRepository.delete(ce);
}
@RequestMapping(method = RequestMethod.DELETE)
public @ResponseBody String delete(@RequestBody(required = true) Dish dsh) throws IOException {
RestaurantEntity e = restaurantRepository.findBySecret(dsh.getSecret());
for(DishEntity d : e.getDishes()) {
if(d.getId().equals(dsh.getId())) {
HashSet<DishEntity> de = new HashSet<>(e.getDishes());
de.remove(d);
e.setDishes(de);
e.setDishListUpdateTimestamp(System.currentTimeMillis());
restaurantRepository.save(e);
d.setDeleteTime(System.currentTimeMillis());
if(d.getCategory() != null) {
CategoryEntity ce = d.getCategory();
d.setCategory(null);
dishRepository.save(d);
cullCategory(e, ce);
} else {
dishRepository.save(d);
}
Server - cullCategory
The cull category call just loops over the dishes to see if a category is unused. If it is missing the method deletes that category.

The delete method also culls the category since the deleted dish might be the last one using a specific category so we need the call there too.
Validator val = new Validator();
val.addConstraint(category,
new LengthConstraint(1, "Category is required"));
val.addConstraint(price,
new NumericConstraint(true, 0, 1000000,
"Price must be a positive number"));
val.addSubmitButtons(ok);
Validation
Back in the client we use the validator API to place a constraint on the category so we’ll always have a category for a dish. We also set a numeric constraint on the price.

Notice that a validator is essential even if you set the text field as a numeric text field. That definition only indicates the type of virtual keyboard used but doesn’t enforce
input since mobile OS’s don’t do that.
Label price = new Label(Restaurant.getInstance().formatCurrency(d.price.get()),
"PriceBadge");
d.price.addChangeListener(pl ->
price.setText(Restaurant.getInstance().formatCurrency(d.price.get())));
Label title = new Label(d.name.get(), “DishName");
d.name.addChangeListener(pl -> title.setText(d.name.get()));
Label description = new Label(d.description.get(), "DishDescription");
d.description.addChangeListener(pl -> description.setText(d.description.get()));
Container titleAndDescription = BoxLayout.encloseY(title, description);
titleAndDescription.setUIID("BlackGradient");
Container cnt = LayeredLayout.encloseIn(sb,
BorderLayout.south(titleAndDescription),
FlowLayout.encloseRight(price)
);
DishListForm
UIID
Foreground white
background 3f51b5
Transparency 200
Alignment right
padding 1mm
margin 0
Margin top 4mm
Next we’ll handle prices on dishes, as you can see in this code we can just add a price label with the right price badge UIID. We use a property listener to automatically
update the price as it changes in the underlying object

We align the price to the right using the flow layout, if we’d have used just text alignment the purple background would have stretched thru the entire width of the space.

The price badge UIID has most of the settings you would expect for color alignment and padding and even a bit of translucency. The thing that pushes it from the top is a
4mm margin on the top side which places it at “just the right place”.
public class DetailsForm extends BaseNavigationForm {
private Builder bld = new Builder();
public DetailsForm(AppSettings app) {
super(app, BoxLayout.y());
TextField emailField = addTextAndLabel(
"E-mail - will receive purchases from the generated app", "", TextField.EMAILADDR);
emailField.addActionListener(e -> {
app.restaurantEmail.set(emailField.getText());
AppStorage.getInstance().update(app);
bld.updateRestaurantSettings(app);
});
TextField urlField = addTextAndLabel("Website URL", "", TextField.URL);
urlField.addActionListener(e -> {
Restaurant.getInstance().website.set(urlField.getText());
bld.updateRestaurantSettings(app);
});
MultiButton address = new MultiButton("Address & Location");
if(Restaurant.getInstance().navigationAddress.get() != null &&
Restaurant.getInstance().navigationAddress.get().length() > 0) {
address.setTextLine2(Restaurant.getInstance().navigationAddress.get());
} else {
address.setTextLine2("...");
}
add(address);
address.addActionListener(e -> new AddressForm().show());
DetailsForm
Next we’ll address the details form which is mostly pretty trivial lets go over it step by step
public class DetailsForm extends BaseNavigationForm {
private Builder bld = new Builder();
public DetailsForm(AppSettings app) {
super(app, BoxLayout.y());
TextField emailField = addTextAndLabel(
"E-mail - will receive purchases from the generated app", "", TextField.EMAILADDR);
emailField.addActionListener(e -> {
app.restaurantEmail.set(emailField.getText());
AppStorage.getInstance().update(app);
bld.updateRestaurantSettings(app);
});
TextField urlField = addTextAndLabel("Website URL", "", TextField.URL);
urlField.addActionListener(e -> {
Restaurant.getInstance().website.set(urlField.getText());
bld.updateRestaurantSettings(app);
});
MultiButton address = new MultiButton("Address & Location");
if(Restaurant.getInstance().navigationAddress.get() != null &&
Restaurant.getInstance().navigationAddress.get().length() > 0) {
address.setTextLine2(Restaurant.getInstance().navigationAddress.get());
} else {
address.setTextLine2("...");
}
add(address);
address.addActionListener(e -> new AddressForm().show());
DetailsForm
I’ve enclosed common code for text field and label creation in the addTextAndLabel method. This ended up reducing only a small part of the clutter and wasn’t as
worthwhile as I had initially hoped
public class DetailsForm extends BaseNavigationForm {
private Builder bld = new Builder();
public DetailsForm(AppSettings app) {
super(app, BoxLayout.y());
TextField emailField = addTextAndLabel(
"E-mail - will receive purchases from the generated app", "", TextField.EMAILADDR);
emailField.addActionListener(e -> {
app.restaurantEmail.set(emailField.getText());
AppStorage.getInstance().update(app);
bld.updateRestaurantSettings(app);
});
TextField urlField = addTextAndLabel("Website URL", "", TextField.URL);
urlField.addActionListener(e -> {
Restaurant.getInstance().website.set(urlField.getText());
bld.updateRestaurantSettings(app);
});
MultiButton address = new MultiButton("Address & Location");
if(Restaurant.getInstance().navigationAddress.get() != null &&
Restaurant.getInstance().navigationAddress.get().length() > 0) {
address.setTextLine2(Restaurant.getInstance().navigationAddress.get());
} else {
address.setTextLine2("...");
}
add(address);
address.addActionListener(e -> new AddressForm().show());
DetailsForm
Address, colors and other elements are represented by a button which will navigate to a deeper “editor” form. This is important as it allows us to keep the UI in this form
relatively simple without too much clutter. 

I considered using something like an accordion UI but using navigation was simpler.
MultiButton styles = new MultiButton("Colors & Fonts");
styles.setTextLine2("...");
add(styles);
styles.addActionListener(e -> new StyleForm().show());
MultiButton about = new MultiButton("About Page");
styles.setTextLine2("...");
add(about);
styles.addActionListener(e -> new AboutRestaurantForm().show());
}
private TextField addTextAndLabel(String label, String value) {
TextField tf = new TextField(value);
tf.setHint(label);
add(new Label(label, "TextFieldLabel")).
add(tf);
return tf;
}
DetailsForm
As I mentioned before addTextFieldAndLabel is relatively simple. It sets the hint and just adds the components into place

More Related Content

Similar to Miscellaneous Features - Part 1 - Transcript.pdf

Architecture - Part 2.pdf
Architecture - Part 2.pdfArchitecture - Part 2.pdf
Architecture - Part 2.pdfShaiAlmog1
 
Architecture - Part 1 - Transcript.pdf
Architecture - Part 1 - Transcript.pdfArchitecture - Part 1 - Transcript.pdf
Architecture - Part 1 - Transcript.pdfShaiAlmog1
 
Initial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdfInitial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdfShaiAlmog1
 
Extracting ui Design - part 5 - transcript.pdf
Extracting ui Design - part 5 - transcript.pdfExtracting ui Design - part 5 - transcript.pdf
Extracting ui Design - part 5 - transcript.pdfShaiAlmog1
 
Creating a Facebook Clone - Part XXIX - Transcript.pdf
Creating a Facebook Clone - Part XXIX - Transcript.pdfCreating a Facebook Clone - Part XXIX - Transcript.pdf
Creating a Facebook Clone - Part XXIX - Transcript.pdfShaiAlmog1
 
ngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency InjectionngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency InjectionDzmitry Ivashutsin
 
Building complex User Interfaces with Sitecore and React
Building complex User Interfaces with Sitecore and ReactBuilding complex User Interfaces with Sitecore and React
Building complex User Interfaces with Sitecore and ReactJonne Kats
 
SQLite and ORM Binding - Part 2.pdf
SQLite and ORM Binding - Part 2.pdfSQLite and ORM Binding - Part 2.pdf
SQLite and ORM Binding - Part 2.pdfShaiAlmog1
 
Restaurant Server - Transcript.pdf
Restaurant Server - Transcript.pdfRestaurant Server - Transcript.pdf
Restaurant Server - Transcript.pdfShaiAlmog1
 
Miscellaneous Features - Part 2 - Transcript.pdf
Miscellaneous Features - Part 2 - Transcript.pdfMiscellaneous Features - Part 2 - Transcript.pdf
Miscellaneous Features - Part 2 - Transcript.pdfShaiAlmog1
 
Solid principles
Solid principlesSolid principles
Solid principlesSahil Kumar
 
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
 
Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitPeter Wilcsinszky
 
SQLite and ORM Binding - Part 1 - Transcript.pdf
SQLite and ORM Binding - Part 1 - Transcript.pdfSQLite and ORM Binding - Part 1 - Transcript.pdf
SQLite and ORM Binding - Part 1 - Transcript.pdfShaiAlmog1
 
Extracting ui Design - part 4 - transcript.pdf
Extracting ui Design - part 4 - transcript.pdfExtracting ui Design - part 4 - transcript.pdf
Extracting ui Design - part 4 - transcript.pdfShaiAlmog1
 
Advanced dot net
Advanced dot netAdvanced dot net
Advanced dot netssa2010
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...Mateusz Zalewski
 

Similar to Miscellaneous Features - Part 1 - Transcript.pdf (20)

Architecture - Part 2.pdf
Architecture - Part 2.pdfArchitecture - Part 2.pdf
Architecture - Part 2.pdf
 
Architecture - Part 1 - Transcript.pdf
Architecture - Part 1 - Transcript.pdfArchitecture - Part 1 - Transcript.pdf
Architecture - Part 1 - Transcript.pdf
 
Initial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdfInitial UI Mockup - Part 3.pdf
Initial UI Mockup - Part 3.pdf
 
Extracting ui Design - part 5 - transcript.pdf
Extracting ui Design - part 5 - transcript.pdfExtracting ui Design - part 5 - transcript.pdf
Extracting ui Design - part 5 - transcript.pdf
 
Creating a Facebook Clone - Part XXIX - Transcript.pdf
Creating a Facebook Clone - Part XXIX - Transcript.pdfCreating a Facebook Clone - Part XXIX - Transcript.pdf
Creating a Facebook Clone - Part XXIX - Transcript.pdf
 
ngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency InjectionngMess: AngularJS Dependency Injection
ngMess: AngularJS Dependency Injection
 
Building complex User Interfaces with Sitecore and React
Building complex User Interfaces with Sitecore and ReactBuilding complex User Interfaces with Sitecore and React
Building complex User Interfaces with Sitecore and React
 
SQLite and ORM Binding - Part 2.pdf
SQLite and ORM Binding - Part 2.pdfSQLite and ORM Binding - Part 2.pdf
SQLite and ORM Binding - Part 2.pdf
 
Restaurant Server - Transcript.pdf
Restaurant Server - Transcript.pdfRestaurant Server - Transcript.pdf
Restaurant Server - Transcript.pdf
 
Miscellaneous Features - Part 2 - Transcript.pdf
Miscellaneous Features - Part 2 - Transcript.pdfMiscellaneous Features - Part 2 - Transcript.pdf
Miscellaneous Features - Part 2 - Transcript.pdf
 
Solid principles
Solid principlesSolid principles
Solid principles
 
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
 
Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnit
 
Redux vs Alt
Redux vs AltRedux vs Alt
Redux vs Alt
 
SQLite and ORM Binding - Part 1 - Transcript.pdf
SQLite and ORM Binding - Part 1 - Transcript.pdfSQLite and ORM Binding - Part 1 - Transcript.pdf
SQLite and ORM Binding - Part 1 - Transcript.pdf
 
Extracting ui Design - part 4 - transcript.pdf
Extracting ui Design - part 4 - transcript.pdfExtracting ui Design - part 4 - transcript.pdf
Extracting ui Design - part 4 - transcript.pdf
 
Advanced redux
Advanced reduxAdvanced redux
Advanced redux
 
Dat402
Dat402Dat402
Dat402
 
Advanced dot net
Advanced dot netAdvanced dot net
Advanced dot net
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
 

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

ERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctBrainSell Technologies
 
Design and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data ScienceDesign and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data SciencePaolo Missier
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingScyllaDB
 
Frisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdf
Frisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdfFrisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdf
Frisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdfAnubhavMangla3
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard37
 
“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdf
“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdf“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdf
“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdfMuhammad Subhan
 
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)Paige Cruz
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsLeah Henrickson
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceSamy Fodil
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptxFIDO Alliance
 
Generative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdfGenerative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdfalexjohnson7307
 
Microsoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireMicrosoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireExakis Nelite
 
Intro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxIntro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxFIDO Alliance
 
AI mind or machine power point presentation
AI mind or machine power point presentationAI mind or machine power point presentation
AI mind or machine power point presentationyogeshlabana357357
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontologyjohnbeverley2021
 
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimaginedpanagenda
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc
 
ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityVictorSzoltysek
 
Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxFIDO Alliance
 

Recently uploaded (20)

ERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage IntacctERP Contender Series: Acumatica vs. Sage Intacct
ERP Contender Series: Acumatica vs. Sage Intacct
 
Design and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data ScienceDesign and Development of a Provenance Capture Platform for Data Science
Design and Development of a Provenance Capture Platform for Data Science
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream Processing
 
Overview of Hyperledger Foundation
Overview of Hyperledger FoundationOverview of Hyperledger Foundation
Overview of Hyperledger Foundation
 
Frisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdf
Frisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdfFrisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdf
Frisco Automating Purchase Orders with MuleSoft IDP- May 10th, 2024.pptx.pdf
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdf
“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdf“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdf
“Iamnobody89757” Understanding the Mysterious of Digital Identity.pdf
 
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
Observability Concepts EVERY Developer Should Know (DevOpsDays Seattle)
 
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on ThanabotsContinuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
Continuing Bonds Through AI: A Hermeneutic Reflection on Thanabots
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
Generative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdfGenerative AI Use Cases and Applications.pdf
Generative AI Use Cases and Applications.pdf
 
Microsoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - QuestionnaireMicrosoft CSP Briefing Pre-Engagement - Questionnaire
Microsoft CSP Briefing Pre-Engagement - Questionnaire
 
Intro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptxIntro to Passkeys and the State of Passwordless.pptx
Intro to Passkeys and the State of Passwordless.pptx
 
AI mind or machine power point presentation
AI mind or machine power point presentationAI mind or machine power point presentation
AI mind or machine power point presentation
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
TrustArc Webinar - Unified Trust Center for Privacy, Security, Compliance, an...
 
ChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps ProductivityChatGPT and Beyond - Elevating DevOps Productivity
ChatGPT and Beyond - Elevating DevOps Productivity
 
Introduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptxIntroduction to FIDO Authentication and Passkeys.pptx
Introduction to FIDO Authentication and Passkeys.pptx
 

Miscellaneous Features - Part 1 - Transcript.pdf

  • 1. Miscellaneous Features - Part I In this section we’ll cover a lot of minor features mostly related to UI that are part of the missing pieces on the road to complete the app
  • 2. Categories ✦We first need to load the categories which we do in the dish list form together with the dish loop © Codename One 2017 all rights reserved Menu menu = Restaurant.getInstance().menu.get(); if(menu.dishes.size() == 0) { for(PropertyBusinessObject d : AppStorage.getInstance().fetchDishes()) { Dish dsh = (Dish)d; menu.dishes.add(dsh); if(!menu.categories.asList().contains(dsh.category.get())) { menu.categories.add(dsh.category.get()); } } } Let’s start with the categories that we can see at the top of the restaurant application. When we fetch a dish we can check if a category is already added and if not we can just add it into the list of categories. This list is used later on when we build the list model for the categories.
  • 3. Adding/Setting a Category ✦In the dish edit form we can set the category with a completion list © Codename One 2017 all rights reserved String[] cats = new String[Restaurant.getInstance().menu.get().categories.size()]; Restaurant.getInstance().menu.get().categories.asList().toArray(cats); AutoCompleteTextField category = new AutoCompleteTextField(cats); if(!Restaurant.getInstance().menu.get().categories.asList().contains(category.getText())) { Restaurant.getInstance().menu.get().categories.add(category.getText()); } d.category.set(category.getText()); ✦When we handle the OK event we can just add the category automatically if it’s missing In the dish edit form we can provide an auto complete text field which allows us to type in a new category or select an existing category. In that same form when a user presses OK we check if the category already exists and if not we add it to the category list. This makes the whole process automatic and effectively removes the Edit/Add/Delete UI for the categories list. That simplifies our work by removing forms we would have built and also simplifies the user experience. Laziness pays off…
  • 4. CategoryEntity ce = null; for(CategoryEntity current : e.getCategories()) { if(current.getName().equals(d.getCategory())) { ce = current; break; } } if(ce == null && d.getCategory() != null) { ce = new CategoryEntity(d.getCategory()); categoryRepository.save(ce); } CategoryEntity oe = de.getCategory(); de.setCategory(ce); dishRepository.save(de); if(d.getId() == null) { Set<DishEntity> dishes = new HashSet<>(e.getDishes()); dishes.add(de); e.setDishes(dishes); restaurantRepository.save(e); } if(oe != null) { cullCategory(e, oe); } Server - DishService Put Dish Here we can see the server code for the categories and you will notice that it is handled as part of the dish update. There is no separate webservice for categories further simplifying this logic. We implicitly create a category if it’s missing and save it to the mysql database. We have a separate call to cull the category which we’ll go into now
  • 5. private void cullCategory(RestaurantEntity e, CategoryEntity ce) { for(DishEntity de : e.getDishes()) { if(ce.equals(de.getCategory())) { return; } } categoryRepository.delete(ce); } @RequestMapping(method = RequestMethod.DELETE) public @ResponseBody String delete(@RequestBody(required = true) Dish dsh) throws IOException { RestaurantEntity e = restaurantRepository.findBySecret(dsh.getSecret()); for(DishEntity d : e.getDishes()) { if(d.getId().equals(dsh.getId())) { HashSet<DishEntity> de = new HashSet<>(e.getDishes()); de.remove(d); e.setDishes(de); e.setDishListUpdateTimestamp(System.currentTimeMillis()); restaurantRepository.save(e); d.setDeleteTime(System.currentTimeMillis()); if(d.getCategory() != null) { CategoryEntity ce = d.getCategory(); d.setCategory(null); dishRepository.save(d); cullCategory(e, ce); } else { dishRepository.save(d); } Server - cullCategory The cull category call just loops over the dishes to see if a category is unused. If it is missing the method deletes that category. The delete method also culls the category since the deleted dish might be the last one using a specific category so we need the call there too.
  • 6. Validator val = new Validator(); val.addConstraint(category, new LengthConstraint(1, "Category is required")); val.addConstraint(price, new NumericConstraint(true, 0, 1000000, "Price must be a positive number")); val.addSubmitButtons(ok); Validation Back in the client we use the validator API to place a constraint on the category so we’ll always have a category for a dish. We also set a numeric constraint on the price. Notice that a validator is essential even if you set the text field as a numeric text field. That definition only indicates the type of virtual keyboard used but doesn’t enforce input since mobile OS’s don’t do that.
  • 7. Label price = new Label(Restaurant.getInstance().formatCurrency(d.price.get()), "PriceBadge"); d.price.addChangeListener(pl -> price.setText(Restaurant.getInstance().formatCurrency(d.price.get()))); Label title = new Label(d.name.get(), “DishName"); d.name.addChangeListener(pl -> title.setText(d.name.get())); Label description = new Label(d.description.get(), "DishDescription"); d.description.addChangeListener(pl -> description.setText(d.description.get())); Container titleAndDescription = BoxLayout.encloseY(title, description); titleAndDescription.setUIID("BlackGradient"); Container cnt = LayeredLayout.encloseIn(sb, BorderLayout.south(titleAndDescription), FlowLayout.encloseRight(price) ); DishListForm UIID Foreground white background 3f51b5 Transparency 200 Alignment right padding 1mm margin 0 Margin top 4mm Next we’ll handle prices on dishes, as you can see in this code we can just add a price label with the right price badge UIID. We use a property listener to automatically update the price as it changes in the underlying object We align the price to the right using the flow layout, if we’d have used just text alignment the purple background would have stretched thru the entire width of the space. The price badge UIID has most of the settings you would expect for color alignment and padding and even a bit of translucency. The thing that pushes it from the top is a 4mm margin on the top side which places it at “just the right place”.
  • 8. public class DetailsForm extends BaseNavigationForm { private Builder bld = new Builder(); public DetailsForm(AppSettings app) { super(app, BoxLayout.y()); TextField emailField = addTextAndLabel( "E-mail - will receive purchases from the generated app", "", TextField.EMAILADDR); emailField.addActionListener(e -> { app.restaurantEmail.set(emailField.getText()); AppStorage.getInstance().update(app); bld.updateRestaurantSettings(app); }); TextField urlField = addTextAndLabel("Website URL", "", TextField.URL); urlField.addActionListener(e -> { Restaurant.getInstance().website.set(urlField.getText()); bld.updateRestaurantSettings(app); }); MultiButton address = new MultiButton("Address & Location"); if(Restaurant.getInstance().navigationAddress.get() != null && Restaurant.getInstance().navigationAddress.get().length() > 0) { address.setTextLine2(Restaurant.getInstance().navigationAddress.get()); } else { address.setTextLine2("..."); } add(address); address.addActionListener(e -> new AddressForm().show()); DetailsForm Next we’ll address the details form which is mostly pretty trivial lets go over it step by step
  • 9. public class DetailsForm extends BaseNavigationForm { private Builder bld = new Builder(); public DetailsForm(AppSettings app) { super(app, BoxLayout.y()); TextField emailField = addTextAndLabel( "E-mail - will receive purchases from the generated app", "", TextField.EMAILADDR); emailField.addActionListener(e -> { app.restaurantEmail.set(emailField.getText()); AppStorage.getInstance().update(app); bld.updateRestaurantSettings(app); }); TextField urlField = addTextAndLabel("Website URL", "", TextField.URL); urlField.addActionListener(e -> { Restaurant.getInstance().website.set(urlField.getText()); bld.updateRestaurantSettings(app); }); MultiButton address = new MultiButton("Address & Location"); if(Restaurant.getInstance().navigationAddress.get() != null && Restaurant.getInstance().navigationAddress.get().length() > 0) { address.setTextLine2(Restaurant.getInstance().navigationAddress.get()); } else { address.setTextLine2("..."); } add(address); address.addActionListener(e -> new AddressForm().show()); DetailsForm I’ve enclosed common code for text field and label creation in the addTextAndLabel method. This ended up reducing only a small part of the clutter and wasn’t as worthwhile as I had initially hoped
  • 10. public class DetailsForm extends BaseNavigationForm { private Builder bld = new Builder(); public DetailsForm(AppSettings app) { super(app, BoxLayout.y()); TextField emailField = addTextAndLabel( "E-mail - will receive purchases from the generated app", "", TextField.EMAILADDR); emailField.addActionListener(e -> { app.restaurantEmail.set(emailField.getText()); AppStorage.getInstance().update(app); bld.updateRestaurantSettings(app); }); TextField urlField = addTextAndLabel("Website URL", "", TextField.URL); urlField.addActionListener(e -> { Restaurant.getInstance().website.set(urlField.getText()); bld.updateRestaurantSettings(app); }); MultiButton address = new MultiButton("Address & Location"); if(Restaurant.getInstance().navigationAddress.get() != null && Restaurant.getInstance().navigationAddress.get().length() > 0) { address.setTextLine2(Restaurant.getInstance().navigationAddress.get()); } else { address.setTextLine2("..."); } add(address); address.addActionListener(e -> new AddressForm().show()); DetailsForm Address, colors and other elements are represented by a button which will navigate to a deeper “editor” form. This is important as it allows us to keep the UI in this form relatively simple without too much clutter. I considered using something like an accordion UI but using navigation was simpler.
  • 11. MultiButton styles = new MultiButton("Colors & Fonts"); styles.setTextLine2("..."); add(styles); styles.addActionListener(e -> new StyleForm().show()); MultiButton about = new MultiButton("About Page"); styles.setTextLine2("..."); add(about); styles.addActionListener(e -> new AboutRestaurantForm().show()); } private TextField addTextAndLabel(String label, String value) { TextField tf = new TextField(value); tf.setHint(label); add(new Label(label, "TextFieldLabel")). add(tf); return tf; } DetailsForm As I mentioned before addTextFieldAndLabel is relatively simple. It sets the hint and just adds the components into place