5. delete.addActionListener(e -> {
previous.addShowListener(prev -> {
previous.removeAllShowListeners();
ToastBar.showMessage("Deleted " + d.name.get() + ". Undo?”,
FontImage.MATERIAL_UNDO, ee -> {
DishListForm dlf = (DishListForm)previous;
dlf.addDish(app, d);
d.id.set(null);
bld.addDish(app, d);
d.id.addChangeListener(pl -> AppStorage.getInstance().insert(d));
});
});
previous.showBack();
bld.deleteDish(app, d);
AppStorage.getInstance().delete(d);
});
DishEditForm
It's Better to Beg for Forgiveness than to Ask for Permission is a proverb sometimes attributed to programming pioneer Grace Hopper. Regardless of the source of that
great quote it’s a wonderful example of good mobile app design. In a mobile app you shouldn’t bother users with “Are you sure” prompts. You should just do what the
user does and provide a way to undo which is exactly what we do when we delete a dish in this code…
6. delete.addActionListener(e -> {
previous.addShowListener(prev -> {
previous.removeAllShowListeners();
ToastBar.showMessage("Deleted " + d.name.get() + ". Undo?”,
FontImage.MATERIAL_UNDO, ee -> {
DishListForm dlf = (DishListForm)previous;
dlf.addDish(app, d);
d.id.set(null);
bld.addDish(app, d);
d.id.addChangeListener(pl -> AppStorage.getInstance().insert(d));
});
});
previous.showBack();
bld.deleteDish(app, d);
AppStorage.getInstance().delete(d);
});
DishEditForm
I’ll skip a bit ahead because the code above is asynchronous. When delete is pressed we show the previous dish list form since the edit form is no longer applicable.
Then we delete the dish in the server and in the storage. You will notice that there is no prompt.
7. delete.addActionListener(e -> {
previous.addShowListener(prev -> {
previous.removeAllShowListeners();
ToastBar.showMessage("Deleted " + d.name.get() + ". Undo?”,
FontImage.MATERIAL_UNDO, ee -> {
DishListForm dlf = (DishListForm)previous;
dlf.addDish(app, d);
d.id.set(null);
bld.addDish(app, d);
d.id.addChangeListener(pl -> AppStorage.getInstance().insert(d));
});
});
previous.showBack();
bld.deleteDish(app, d);
AppStorage.getInstance().delete(d);
});
DishEditForm
Now we need to show a UI that allows the user to undo the delete operation but here is the problem… We just navigated to the dish list from the form we were in since
the edit form is no longer applicable. So we use a listener on the parent form so we will know when it is shown again. The problem is that if we do that without the next
line we’ll get prompts every time we enter that form after the deletion.
So the obvious question is: why didn’t we just call removeShowListener(this). Well, funny story… This is a lambda expression and here this is always the parent class so
removeShowListener(this) won’t have the desired affect. So the solution is a bit of a hack but it was either this or use inner classes so I chose this hack.
8. delete.addActionListener(e -> {
previous.addShowListener(prev -> {
previous.removeAllShowListeners();
ToastBar.showMessage("Deleted " + d.name.get() + ". Undo?”,
FontImage.MATERIAL_UNDO, ee -> {
DishListForm dlf = (DishListForm)previous;
dlf.addDish(app, d);
d.id.set(null);
bld.addDish(app, d);
d.id.addChangeListener(pl -> AppStorage.getInstance().insert(d));
});
});
previous.showBack();
bld.deleteDish(app, d);
AppStorage.getInstance().delete(d);
});
DishEditForm
This is relatively simple, we are now in the right form after the deletion and I can now show the undo toast message that will appear in the bottom of the form. If a user
taps this popup it will undo the deletion instantly
9. delete.addActionListener(e -> {
previous.addShowListener(prev -> {
previous.removeAllShowListeners();
ToastBar.showMessage("Deleted " + d.name.get() + ". Undo?”,
FontImage.MATERIAL_UNDO, ee -> {
DishListForm dlf = (DishListForm)previous;
dlf.addDish(app, d);
d.id.set(null);
bld.addDish(app, d);
d.id.addChangeListener(pl -> AppStorage.getInstance().insert(d));
});
});
previous.showBack();
bld.deleteDish(app, d);
AppStorage.getInstance().delete(d);
});
DishEditForm
The undo code doesn’t really “undo” as there is no meaningful way to undo in code. We just re-add the dish.
10. ok.addActionListener(e -> {
previous.showBack();
d.name.set(title.getText());
d.description.set(description.getText());
try {
d.price.set(Double.parseDouble(price.getText()));
} catch(NumberFormatException err) {
Log.e(err);
ToastBar.showErrorMessage("Malformed price");
}
bld.updateDish(app, d);
Restaurant.getInstance().menu.get().dishes.add(d);
if(d.id.get() != null) {
AppStorage.getInstance().update(d);
}
//bld.updateDishImage(app, d);
});
DishEditForm
By comparison saving the dish is much easier and practically trivial. All of the logic to save a dish to the server and update it to storage is just a couple of lines of code
11. TextField title = new TextField(app.name.get());
title.setUIID("NavigationTitle");
title.addActionListener(a -> {
app.name.set(title.getText());
AppStorage.getInstance().update(app);
});
TextField tagline = new TextField(app.tagline.get());
tagline.setUIID("Tagline");
tagline.addActionListener(a -> {
app.tagline.set(tagline.getText());
AppStorage.getInstance().update(app);
});
BaseNavigationForm
In the case of the tagline & title we currently only save them locally but we will add the server update code as well