The document discusses changes made to integrate a model with the UI for a restaurant ordering application. Key points:
1) The code was updated to retrieve currency formatting and dish data from the restaurant model instead of hardcoded values, integrating the model with the UI.
2) A listener was added to track changes to the dishes map to automatically recalculate the order total when items are added or removed.
3) Similar code updates were made to the checkout and menu forms to populate them with data from the restaurant model.
4) The contact form retrieves location and phone data from the model instead of hardcoded values. Ordering functionality was also updated to use the model.
5) Top-down development,
How to Check GPS Location with a Live Tracker in Pakistan
Architecture - Part 2 - Transcript.pdf
1. Architecture - Part II
Next on the agenda is integrating the model that we developed with the UI that we built…
2. Label currentOrderValue = new Label("Your Order: " +
Restaurant.getInstance().formatCurrency(0),
"YourOrder");
Restaurant.getInstance().cart.get().
dishesQuantity.addChangeListener(pl -> {
double totalPriceValue = 0;
for(Map.Entry<Dish, Integer> currentDish :
Restaurant.getInstance().cart.get().dishesQuantity) {
totalPriceValue += (currentDish.getKey().price.get() *
currentDish.getValue());
}
currentOrderValue.setText("Your Order: " +
Restaurant.getInstance().
formatCurrency(totalPriceValue));
revalidate();
});
Base Form
First, I didn’t mention the format currency call. Initially when I started working on the code I used the L10NManager to format the code which made sense at a glance.
However, currency is something we get from the restaurant itself and it should handle the currency type.
Adding the dishes is code we already have however, this second block of code is pretty cool…
3. Label currentOrderValue = new Label("Your Order: " +
Restaurant.getInstance().formatCurrency(0),
"YourOrder");
Restaurant.getInstance().cart.get().
dishesQuantity.addChangeListener(pl -> {
double totalPriceValue = 0;
for(Map.Entry<Dish, Integer> currentDish :
Restaurant.getInstance().cart.get().dishesQuantity) {
totalPriceValue += (currentDish.getKey().price.get() *
currentDish.getValue());
}
currentOrderValue.setText("Your Order: " +
Restaurant.getInstance().
formatCurrency(totalPriceValue));
revalidate();
});
Base Form
First I bind a listener to the dish quantity which allows me to track changes to the map of dishes to the quantity of each. That means that every time a dish is added or
removed in the map of dishes (regardless of the source of the change) we can get an event and recalculate the amount in the order.
Updating the amount is literally as trivial as looping over the dishes and adding up the amounts then setting it to the label.
Notice that we call revalidate at the bottom since the label might have a longer string as a result and we might need to enlarge the space allocated for it
4. private void updatePrice() {
double totalPriceValue = 0;
for(Map.Entry<Dish, Integer> currentDish :
Restaurant.getInstance().cart.get().dishesQuantity) {
totalPriceValue += (currentDish.getKey().price.get() * currentDish.getValue());
}
totalPrice.setText("Total: " + Restaurant.getInstance().formatCurrency(totalPriceValue));
totalPrice.getParent().revalidate();
}
private Container createShoppingCartContainer(Dish di, int quantity) {
// snipped…
Container dishContainer = BoxLayout.encloseX(
FlowLayout.encloseMiddle(quantityButton),
new Label(di.thumbnail.get(), "UnmarginedLabel"),
FlowLayout.encloseMiddle(
BoxLayout.encloseY(
new Label(di.name.get(), "DishCheckoutTitle"),
new Label(Restaurant.getInstance().formatCurrency(di.price.get()), "CheckoutPrice")
)
)
);
Checkout Form
We have very similar code in the checkout form, it updates the total value based on the dish map. In this case we don’t need the listeners since the checkout form only
provides one way to edit the data.
The dish container hasn’t changed much so I snipped out most of the code
5. quantityButton.addActionListener(e -> {
if(quantityButton.getSelectedString().equals(PICKER_STRINGS[0])) {
Display.getInstance().callSerially(() -> {
dishContainer.setX(Display.getInstance().getDisplayWidth());
Container p = dishContainer.getParent();
p.animateUnlayoutAndWait(250, 255);
dishContainer.remove();
p.animateLayoutAndWait(200);
updatePrice();
});
} else {
updatePrice();
}
});
return dishContainer;
}
Checkout Form
However the animation portion of the removal now needs to update the price after the animation completed. Notice we call updatePrice only after the animation so the
repaint of the price won’t interfere with the running animation
6. Restaurant r = Restaurant.getInstance();
Coord crd = new Coord(r.latitude.get(), r.longitude.get());
MapContainer map = new MapContainer(“google-key");
map.addMarker(null, crd, r.name.get(), r.tagline.get(), null);
map.setCameraPosition(crd);
TextArea address = new TextArea(r.address.get());
address.setEditable(false);
address.setUIID("MapAddressText");
Button phone = new Button("", "ShoppingCart");
FontImage.setMaterialIcon(phone, FontImage.MATERIAL_CALL);
phone.addActionListener(e -> Display.getInstance().dial(r.phone.get()));
Button navigate = new Button("", "ShoppingCart");
FontImage.setMaterialIcon(navigate, FontImage.MATERIAL_NAVIGATION);
navigate.addActionListener(e ->
Display.getInstance().openNativeNavigationApp(r.navigationAddress.get()));
Contact Us Form
The contact us form is practically the same as before and the only major difference is that the formerly hardcoded data is now entirely from the restaurant class.
7. List<String> l = new List<String>(new DefaultListModel<>(
Restaurant.getInstance().
menu.get().
categories.asList()))
protected Container createContent() {
Container c = new Container(BoxLayout.y());
for(Dish currentDish : Restaurant.getInstance().menu.get().dishes) {
c.add(createDishContainer(currentDish));
}
c.setScrollableY(true);
c.setScrollVisible(false);
return c;
}
order.addActionListener(e -> {
Order o = Restaurant.getInstance().cart.get();
if(o.dishesQuantity.get(dish) != null) {
o.dishesQuantity.put(dish, o.dishesQuantity.get(dish) + 1);
} else {
o.dishesQuantity.put(dish, 1);
}
});
Main Menu Form
The main menu form has 3 interesting pieces of code I’d like to focus on. First the code to create the categories list is no longer hardcoded
8. List<String> l = new List<String>(new DefaultListModel<>(
Restaurant.getInstance().
menu.get().
categories.asList()))
protected Container createContent() {
Container c = new Container(BoxLayout.y());
for(Dish currentDish : Restaurant.getInstance().menu.get().dishes) {
c.add(createDishContainer(currentDish));
}
c.setScrollableY(true);
c.setScrollVisible(false);
return c;
}
order.addActionListener(e -> {
Order o = Restaurant.getInstance().cart.get();
if(o.dishesQuantity.get(dish) != null) {
o.dishesQuantity.put(dish, o.dishesQuantity.get(dish) + 1);
} else {
o.dishesQuantity.put(dish, 1);
}
});
Main Menu Form
The second part is the content container which loops over the dishes in the main menu and places them into the UI. Unlike the previous code this now uses the
restaurant model to show the data
9. List<String> l = new List<String>(new DefaultListModel<>(
Restaurant.getInstance().
menu.get().
categories.asList()))
protected Container createContent() {
Container c = new Container(BoxLayout.y());
for(Dish currentDish : Restaurant.getInstance().menu.get().dishes) {
c.add(createDishContainer(currentDish));
}
c.setScrollableY(true);
c.setScrollVisible(false);
return c;
}
order.addActionListener(e -> {
Order o = Restaurant.getInstance().cart.get();
if(o.dishesQuantity.get(dish) != null) {
o.dishesQuantity.put(dish, o.dishesQuantity.get(dish) + 1);
} else {
o.dishesQuantity.put(dish, 1);
}
});
Main Menu Form
The final part is the code which adds a dish. Order is the button you see here, it adds the item to the order total. Notice that we just put a dish into the order and update
the quantity… Nothing else. The event handling code updates the subtotal of the order seamlessly!
10. What did we learn?
✦ Designing an object model is easier when we
already built the UI
✦ Top -> Bottom is a very convenient way to quickly
build an app
I don’t always use the top to bottom approach of development but I like it more. When I take that approach I can quickly bring non-coders into the “circle” of discussion
as the UI aspect is instantly communicable and everything else becomes far easier.
There are always exceptions to the rule, for instance sometimes we build apps for companies that have extensive backends and no front-ends. In those cases it’s
sometimes easier to just build the mapping to the backend and then build a UI around that.
In both cases I’m firmly in the camp of running quickly thru the design. You can’t debug a design. Unless you are building a mission critical app your time might be better
spent coding than overthinking a design
11. Thank You!
Thanks for watching I hope you found this educational. Please join the discussion in the comments section and let me know what you think!