Fork us on GitHub

Ratatouille's Restaurant In Code

How to build a simple restaurant app in Codename One
Post Image

Ratatouille's Restaurant In Code

One of my favorite Pixar movies is Ratatouille, maybe because I'm such a glutton. So when I was thinking about the next tutorial/demo and the idea of a restaurant app came up I knew it had to be based on Ratatouille. This is a relatively simple demo that can literally fit in a single blog post all the way thru and the real cool thing about it is that you can try the JavaScript version right now from your browser without compiling anything...

The demo shows off how attractive a really simple UI can be with the right font face and a few images/transparency effects. This is further emphasized via the nice expansion animation when clicking on an image. We also demonstrate navigation, maps and integration with table ordering systems as part of the demo (haven't tested the latter since its only supposed to work in the states). You can check out the full source code of the demo in github.

The Main Class

The main class is pretty trivial with mostly boilerplate code:

public void start() {
    if(current != null){
        current.show();
        return;
    }
    new MainUI(theme).show();
}

This effectively says that all the logic is in the MainUI class.

The Main UI Class

This class is slightly larger so we'll break it down to obvious pieces of code:

public MainUI(Resources theme) {
    super(RESTAURANT_NAME);
    this.theme = theme;
    Toolbar t = new Toolbar();
    setToolBar(t);
    t.setScrollOffUponContentPane(true);

    Label rat = new Label(theme.getImage("round_logo.png"));
    rat.setTextPosition(Label.BOTTOM);
    rat.setText(RESTAURANT_NAME);
    rat.setUIID("SideMenuLogo");
    t.addComponentToSideMenu(rat);
    setLayout(new BorderLayout());

    Container dishes = createDishesContainer();
    addComponent(BorderLayout.CENTER, dishes);
    revalidate();

    Style iconStyle = UIManager.getInstance().getComponentStyle("SideCommandIcon");

    t.addCommandToSideMenu(new Command("Menu", FontImage.create(" \ue93f ", iconStyle)) {
        @Override
        public void actionPerformed(ActionEvent evt) {
            showDishesContainer();
        }
    });
    if(INCLUDE_RESERVATIONS) {
        t.addCommandToSideMenu(new Command("Reservation", FontImage.create(" \ue838 ", iconStyle)) {
            @Override
            public void actionPerformed(ActionEvent evt) {
                Display.getInstance().execute("reserve://opentable.com/" + OPEN_TABLE_RESERVATION_ID +  "?partySize=2");
            }
        });
    }
    t.addCommandToSideMenu(new Command("Find Us", FontImage.create(" \ue8d5 ", iconStyle)) {
        @Override
        public void actionPerformed(ActionEvent evt) {
            showMap();
        }
    });
    t.addCommandToSideMenu(new Command("Contact Us", FontImage.create(" \ue86b ", iconStyle)) {
        @Override
        public void actionPerformed(ActionEvent evt) {
            showContactUs();
        }
    });
    t.addCommandToSideMenu(new Command("Navigate", FontImage.create(" \ue85b ", iconStyle)) {
        @Override
        public void actionPerformed(ActionEvent evt) {
            Display.getInstance().openNativeNavigationApp(RESTAURANT_LATITUDE, RESTAURANT_LONGITUDE);
        }
    });
}

That's pretty much the whole application. You'll notice that commands are added to the side menu with icon fonts, that demo predated our new Material design icons and new native fonts so it uses neither. Newer code would be smaller and simpler.
The "rat" label above shows the rounded version of the logo on the side menu that slides out as such:

Sidemenu

The main UI itself is implemented in the createDishesContainer call:

private Container createDishesContainer() {
    Container cnt = new Container(new BoxLayout(BoxLayout.Y_AXIS));
    cnt.setScrollableY(true);

    // allows elements to slide into view
    for(Dish d : DISHES) {
        Component dish = createDishComponent(d);
        cnt.addComponent(dish);            
    }        
    return cnt;
}

private Container createDishComponent(Dish d) {
    Image img = theme.getImage(d.getImageName());
    Container mb = new Container(new BorderLayout());
    mb.getUnselectedStyle().setBgImage(img);
    mb.getSelectedStyle().setBgImage(img);
    mb.getPressedStyle().setBgImage(img);
    mb.getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
    mb.getSelectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
    mb.getPressedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);

    Container box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
    Button title = new Button(d.getDishName());
    title.setUIID("DishTitle");
    Label highlights = new Label(d.getHighlights());
    TextArea details = new TextArea(d.getFullDescription());
    details.setUIID("DishBody");
    highlights.setUIID("DishBody");
    Label price = new Label(d.getPrice());
    price.setUIID("DishPrice");
    box.addComponent(title);
    box.addComponent(highlights);

    Container boxAndPrice = new Container(new BorderLayout());
    boxAndPrice.addComponent(BorderLayout.CENTER, box);
    boxAndPrice.addComponent(BorderLayout.EAST, price);
    mb.addComponent(BorderLayout.SOUTH, boxAndPrice);

    mb.setLeadComponent(title);

    title.addActionListener((e) -> {
        if(highlights.getParent() != null) {
            box.removeComponent(highlights);
            box.addComponent(details);
        } else {
            box.removeComponent(details);
            box.addComponent(highlights);
        }
        mb.getParent().animateLayout(300);
    });
    return mb;
}

Here we just loop and create individual dish objects then create the expand/contract effect. This is done by adding/removing the details component and invoking the animateLayout method.

Share this Post:

Posted by Shai Almog

Shai is the co-founder of Codename One. He's been a professional programmer for over 25 years. During that time he has worked with dozens of companies including Sun Microsystems.
For more follow Shai on Twitter & github.