SlideShare a Scribd company logo
Finishing the App - Part I
The Server
✦The server code is attached to this course but I’m not
discussing it
✦I want to avoid that complexity in this course and I’m
keeping it for the app builder course
© Codename One 2017 all rights reserved
Finishing the App
✦ Finishing an app is the hardest thing for most
developers
✦ We procrastinate and find other things that need
doing and can’t make it “past the finish line”
✦ The trick is to decide on a very restricted list of
features and work thru them until the beta
✦ Don’t add to that list!

It needs to be complete
© Codename One 2017 all rights reserved
List of things to fix
✦Bind data to the server
✦Add support for delivery address collection
✦Add some validation such as minimum order
✦Fix styling of components for pressed states
✦Implement search in the client
✦Implement selection based on dish category
✦Store dish image data in the server/database and fetch/
cache dynamically
© Codename One 2017 all rights reserved
public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
@Override
protected Container createContent() {
Container c = new Container(BoxLayout.y());
final Menu m = Restaurant.getInstance().menu.get();
if(m.dishes.size() == 0) {
if(DishService.hasCachedDishList()) {
DishService.loadDishesFromCache();
}
}
if(m.dishes.size() > 0) {
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.addPullToRefresh(() -> {
DishService.updateDishesFromServerSync();
c.removeAll();
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.revalidate();
});
} else {
MainMenuForm
@Override
protected Container createContent() {
Container c = new Container(BoxLayout.y());
final Menu m = Restaurant.getInstance().menu.get();
if(m.dishes.size() == 0) {
if(DishService.hasCachedDishList()) {
DishService.loadDishesFromCache();
}
}
if(m.dishes.size() > 0) {
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.addPullToRefresh(() -> {
DishService.updateDishesFromServerSync();
c.removeAll();
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.revalidate();
});
} else {
MainMenuForm
} else {
final Container infi = FlowLayout.encloseCenter(new InfiniteProgress());
c.add(infi);
m.dishDownloadFinished.addChangeListener(p -> {
c.removeAll();
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
categoryModel.removeAll();
for(String s : m.categories) {
categoryModel.addItem(s);
}
c.revalidate();
});
}
c.setScrollableY(true);
c.setScrollVisible(false);
dishesContainer = c;
return c;
}
MainMenuForm

More Related Content

Similar to Finishing the App - Part 1.pdf

Testdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinnerTestdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinner
Truls Jørgensen
 
Spca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_serviceSpca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_service
NCCOMMS
 

Similar to Finishing the App - Part 1.pdf (20)

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
 
Advanced redux
Advanced reduxAdvanced redux
Advanced redux
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Miscellaneous Features - Part 1.pdf
Miscellaneous Features - Part 1.pdfMiscellaneous Features - Part 1.pdf
Miscellaneous Features - Part 1.pdf
 
Reduxing like a pro
Reduxing like a proReduxing like a pro
Reduxing like a pro
 
SQLite and ORM Binding - Part 2 - Transcript.pdf
SQLite and ORM Binding - Part 2 - Transcript.pdfSQLite and ORM Binding - Part 2 - Transcript.pdf
SQLite and ORM Binding - Part 2 - Transcript.pdf
 
NoSQL meets Microservices
NoSQL meets MicroservicesNoSQL meets Microservices
NoSQL meets Microservices
 
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
 
Pengenalan blaast platform sdk
Pengenalan blaast platform sdkPengenalan blaast platform sdk
Pengenalan blaast platform sdk
 
Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...
Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...
Lviv MDDay 2014. Ігор Коробка “забезпечення базової безпеки в андроїд аплікац...
 
NoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael HacksteinNoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices - Michael Hackstein
 
Restaurant Server - Transcript.pdf
Restaurant Server - Transcript.pdfRestaurant Server - Transcript.pdf
Restaurant Server - Transcript.pdf
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
Stop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScriptStop Making Excuses and Start Testing Your JavaScript
Stop Making Excuses and Start Testing Your JavaScript
 
Testdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinnerTestdrevet javautvikling på objektorienterte skinner
Testdrevet javautvikling på objektorienterte skinner
 
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
MBL301 Data Persistence to Amazon Dynamodb for Mobile Apps - AWS re: Invent 2012
 
SQLite and ORM Binding - Part 1.pdf
SQLite and ORM Binding - Part 1.pdfSQLite and ORM Binding - Part 1.pdf
SQLite and ORM Binding - Part 1.pdf
 
Spca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_serviceSpca2014 hillier build your_own_rest_service
Spca2014 hillier build your_own_rest_service
 
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
 
APIs, APIs Everywhere!
APIs, APIs Everywhere!APIs, APIs Everywhere!
APIs, APIs Everywhere!
 

More from ShaiAlmog1

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

Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Peter Udo Diehl
 

Recently uploaded (20)

PLAI - Acceleration Program for Generative A.I. Startups
PLAI - Acceleration Program for Generative A.I. StartupsPLAI - Acceleration Program for Generative A.I. Startups
PLAI - Acceleration Program for Generative A.I. Startups
 
Agentic RAG What it is its types applications and implementation.pdf
Agentic RAG What it is its types applications and implementation.pdfAgentic RAG What it is its types applications and implementation.pdf
Agentic RAG What it is its types applications and implementation.pdf
 
A Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System StrategyA Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System Strategy
 
"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi"Impact of front-end architecture on development cost", Viktor Turskyi
"Impact of front-end architecture on development cost", Viktor Turskyi
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
Speed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in MinutesSpeed Wins: From Kafka to APIs in Minutes
Speed Wins: From Kafka to APIs in Minutes
 
WSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptxWSO2CONMay2024OpenSourceConferenceDebrief.pptx
WSO2CONMay2024OpenSourceConferenceDebrief.pptx
 
IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024
 
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
 
Connecting the Dots in Product Design at KAYAK
Connecting the Dots in Product Design at KAYAKConnecting the Dots in Product Design at KAYAK
Connecting the Dots in Product Design at KAYAK
 
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
Measures in SQL (a talk at SF Distributed Systems meetup, 2024-05-22)
 
Strategic AI Integration in Engineering Teams
Strategic AI Integration in Engineering TeamsStrategic AI Integration in Engineering Teams
Strategic AI Integration in Engineering Teams
 
In-Depth Performance Testing Guide for IT Professionals
In-Depth Performance Testing Guide for IT ProfessionalsIn-Depth Performance Testing Guide for IT Professionals
In-Depth Performance Testing Guide for IT Professionals
 
IESVE for Early Stage Design and Planning
IESVE for Early Stage Design and PlanningIESVE for Early Stage Design and Planning
IESVE for Early Stage Design and Planning
 
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
Integrating Telephony Systems with Salesforce: Insights and Considerations, B...
 
Intelligent Gimbal FINAL PAPER Engineering.pdf
Intelligent Gimbal FINAL PAPER Engineering.pdfIntelligent Gimbal FINAL PAPER Engineering.pdf
Intelligent Gimbal FINAL PAPER Engineering.pdf
 
Transforming The New York Times: Empowering Evolution through UX
Transforming The New York Times: Empowering Evolution through UXTransforming The New York Times: Empowering Evolution through UX
Transforming The New York Times: Empowering Evolution through UX
 
Enterprise Security Monitoring, And Log Management.
Enterprise Security Monitoring, And Log Management.Enterprise Security Monitoring, And Log Management.
Enterprise Security Monitoring, And Log Management.
 
Custom Approval Process: A New Perspective, Pavel Hrbacek & Anindya Halder
Custom Approval Process: A New Perspective, Pavel Hrbacek & Anindya HalderCustom Approval Process: A New Perspective, Pavel Hrbacek & Anindya Halder
Custom Approval Process: A New Perspective, Pavel Hrbacek & Anindya Halder
 

Finishing the App - Part 1.pdf

  • 1. Finishing the App - Part I
  • 2. The Server ✦The server code is attached to this course but I’m not discussing it ✦I want to avoid that complexity in this course and I’m keeping it for the app builder course © Codename One 2017 all rights reserved
  • 3. Finishing the App ✦ Finishing an app is the hardest thing for most developers ✦ We procrastinate and find other things that need doing and can’t make it “past the finish line” ✦ The trick is to decide on a very restricted list of features and work thru them until the beta ✦ Don’t add to that list!
 It needs to be complete © Codename One 2017 all rights reserved
  • 4. List of things to fix ✦Bind data to the server ✦Add support for delivery address collection ✦Add some validation such as minimum order ✦Fix styling of components for pressed states ✦Implement search in the client ✦Implement selection based on dish category ✦Store dish image data in the server/database and fetch/ cache dynamically © Codename One 2017 all rights reserved
  • 5. public class DishService { public static boolean hasCachedDishList() { return Storage.getInstance().exists("DishListCache"); } public static void loadDishesFromCache() { JSONParser p = new JSONParser(); try { Map<String, Object> m = p.parseJSON(new InputStreamReader( Storage.getInstance().createInputStream("DishListCache"), "UTF-8")); List<Object> l = (List<Object>)m.get("dishes"); Restaurant.getInstance().menu.get().dishes.clear(); for(Object o : l) { Dish d = new Dish(); d.getPropertyIndex().populateFromMap((Map)o); Restaurant.getInstance().menu.get().dishes.add(d); } List<String> cats = (List<String>)m.get("categories"); Restaurant.getInstance().menu.get().categories.clear(); for(String str : cats) { Restaurant.getInstance().menu.get().categories.add(str); } if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) { Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE); } } catch(IOException err) { Log.e(err); ToastBar.showErrorMessage("Error loading list of dishes: " + err); Log.sendLog(); DishService (Client)
  • 6. public class DishService { public static boolean hasCachedDishList() { return Storage.getInstance().exists("DishListCache"); } public static void loadDishesFromCache() { JSONParser p = new JSONParser(); try { Map<String, Object> m = p.parseJSON(new InputStreamReader( Storage.getInstance().createInputStream("DishListCache"), "UTF-8")); List<Object> l = (List<Object>)m.get("dishes"); Restaurant.getInstance().menu.get().dishes.clear(); for(Object o : l) { Dish d = new Dish(); d.getPropertyIndex().populateFromMap((Map)o); Restaurant.getInstance().menu.get().dishes.add(d); } List<String> cats = (List<String>)m.get("categories"); Restaurant.getInstance().menu.get().categories.clear(); for(String str : cats) { Restaurant.getInstance().menu.get().categories.add(str); } if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) { Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE); } } catch(IOException err) { Log.e(err); ToastBar.showErrorMessage("Error loading list of dishes: " + err); Log.sendLog(); DishService (Client)
  • 7. public class DishService { public static boolean hasCachedDishList() { return Storage.getInstance().exists("DishListCache"); } public static void loadDishesFromCache() { JSONParser p = new JSONParser(); try { Map<String, Object> m = p.parseJSON(new InputStreamReader( Storage.getInstance().createInputStream("DishListCache"), "UTF-8")); List<Object> l = (List<Object>)m.get("dishes"); Restaurant.getInstance().menu.get().dishes.clear(); for(Object o : l) { Dish d = new Dish(); d.getPropertyIndex().populateFromMap((Map)o); Restaurant.getInstance().menu.get().dishes.add(d); } List<String> cats = (List<String>)m.get("categories"); Restaurant.getInstance().menu.get().categories.clear(); for(String str : cats) { Restaurant.getInstance().menu.get().categories.add(str); } if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) { Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE); } } catch(IOException err) { Log.e(err); ToastBar.showErrorMessage("Error loading list of dishes: " + err); Log.sendLog(); DishService (Client)
  • 8. public class DishService { public static boolean hasCachedDishList() { return Storage.getInstance().exists("DishListCache"); } public static void loadDishesFromCache() { JSONParser p = new JSONParser(); try { Map<String, Object> m = p.parseJSON(new InputStreamReader( Storage.getInstance().createInputStream("DishListCache"), "UTF-8")); List<Object> l = (List<Object>)m.get("dishes"); Restaurant.getInstance().menu.get().dishes.clear(); for(Object o : l) { Dish d = new Dish(); d.getPropertyIndex().populateFromMap((Map)o); Restaurant.getInstance().menu.get().dishes.add(d); } List<String> cats = (List<String>)m.get("categories"); Restaurant.getInstance().menu.get().categories.clear(); for(String str : cats) { Restaurant.getInstance().menu.get().categories.add(str); } if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) { Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE); } } catch(IOException err) { Log.e(err); ToastBar.showErrorMessage("Error loading list of dishes: " + err); Log.sendLog(); DishService (Client)
  • 9. public class DishService { public static boolean hasCachedDishList() { return Storage.getInstance().exists("DishListCache"); } public static void loadDishesFromCache() { JSONParser p = new JSONParser(); try { Map<String, Object> m = p.parseJSON(new InputStreamReader( Storage.getInstance().createInputStream("DishListCache"), "UTF-8")); List<Object> l = (List<Object>)m.get("dishes"); Restaurant.getInstance().menu.get().dishes.clear(); for(Object o : l) { Dish d = new Dish(); d.getPropertyIndex().populateFromMap((Map)o); Restaurant.getInstance().menu.get().dishes.add(d); } List<String> cats = (List<String>)m.get("categories"); Restaurant.getInstance().menu.get().categories.clear(); for(String str : cats) { Restaurant.getInstance().menu.get().categories.add(str); } if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) { Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE); } } catch(IOException err) { Log.e(err); ToastBar.showErrorMessage("Error loading list of dishes: " + err); Log.sendLog(); DishService (Client)
  • 10. public static void updateDishesFromServerSync() { NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer()); } public static void updateDishesFromServerAsync() { NetworkManager.getInstance().addToQueue(updateDishesFromServer()); } private static ConnectionRequest updateDishesFromServer() { ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) { private boolean autoLoad; protected void readResponse(InputStream input) throws IOException { JSONParser p = new JSONParser(); Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8")); String stamp = (String)m.get("stamp"); if(stamp != null) { Preferences.set("lastTimeStamp", stamp); OutputStream o = Storage.getInstance().createOutputStream("DishListCache"); o.write(Result.fromContent(m).toString().getBytes()); o.close(); autoLoad = true; } } protected void postResponse() { if(autoLoad) { loadDishesFromCache(); } } }; cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0")); cr.addArgument("appId", MyRestaurant.APP_AUTH); return cr; DishService (Client)
  • 11. public static void updateDishesFromServerSync() { NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer()); } public static void updateDishesFromServerAsync() { NetworkManager.getInstance().addToQueue(updateDishesFromServer()); } private static ConnectionRequest updateDishesFromServer() { ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) { private boolean autoLoad; protected void readResponse(InputStream input) throws IOException { JSONParser p = new JSONParser(); Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8")); String stamp = (String)m.get("stamp"); if(stamp != null) { Preferences.set("lastTimeStamp", stamp); OutputStream o = Storage.getInstance().createOutputStream("DishListCache"); o.write(Result.fromContent(m).toString().getBytes()); o.close(); autoLoad = true; } } protected void postResponse() { if(autoLoad) { loadDishesFromCache(); } } }; cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0")); cr.addArgument("appId", MyRestaurant.APP_AUTH); return cr; DishService (Client)
  • 12. public static void updateDishesFromServerSync() { NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer()); } public static void updateDishesFromServerAsync() { NetworkManager.getInstance().addToQueue(updateDishesFromServer()); } private static ConnectionRequest updateDishesFromServer() { ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) { private boolean autoLoad; protected void readResponse(InputStream input) throws IOException { JSONParser p = new JSONParser(); Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8")); String stamp = (String)m.get("stamp"); if(stamp != null) { Preferences.set("lastTimeStamp", stamp); OutputStream o = Storage.getInstance().createOutputStream("DishListCache"); o.write(Result.fromContent(m).toString().getBytes()); o.close(); autoLoad = true; } } protected void postResponse() { if(autoLoad) { loadDishesFromCache(); } } }; cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0")); cr.addArgument("appId", MyRestaurant.APP_AUTH); return cr; DishService (Client)
  • 13. public static void updateDishesFromServerSync() { NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer()); } public static void updateDishesFromServerAsync() { NetworkManager.getInstance().addToQueue(updateDishesFromServer()); } private static ConnectionRequest updateDishesFromServer() { ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) { private boolean autoLoad; protected void readResponse(InputStream input) throws IOException { JSONParser p = new JSONParser(); Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8")); String stamp = (String)m.get("stamp"); if(stamp != null) { Preferences.set("lastTimeStamp", stamp); OutputStream o = Storage.getInstance().createOutputStream("DishListCache"); o.write(Result.fromContent(m).toString().getBytes()); o.close(); autoLoad = true; } } protected void postResponse() { if(autoLoad) { loadDishesFromCache(); } } }; cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0")); cr.addArgument("appId", MyRestaurant.APP_AUTH); return cr; DishService (Client)
  • 14. public static void updateDishesFromServerSync() { NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer()); } public static void updateDishesFromServerAsync() { NetworkManager.getInstance().addToQueue(updateDishesFromServer()); } private static ConnectionRequest updateDishesFromServer() { ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) { private boolean autoLoad; protected void readResponse(InputStream input) throws IOException { JSONParser p = new JSONParser(); Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8")); String stamp = (String)m.get("stamp"); if(stamp != null) { Preferences.set("lastTimeStamp", stamp); OutputStream o = Storage.getInstance().createOutputStream("DishListCache"); o.write(Result.fromContent(m).toString().getBytes()); o.close(); autoLoad = true; } } protected void postResponse() { if(autoLoad) { loadDishesFromCache(); } } }; cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0")); cr.addArgument("appId", MyRestaurant.APP_AUTH); return cr; DishService (Client)
  • 15. @Override protected Container createContent() { Container c = new Container(BoxLayout.y()); final Menu m = Restaurant.getInstance().menu.get(); if(m.dishes.size() == 0) { if(DishService.hasCachedDishList()) { DishService.loadDishesFromCache(); } } if(m.dishes.size() > 0) { for(Dish currentDish : m.dishes) { c.add(createDishContainer(currentDish)); } c.addPullToRefresh(() -> { DishService.updateDishesFromServerSync(); c.removeAll(); for(Dish currentDish : m.dishes) { c.add(createDishContainer(currentDish)); } c.revalidate(); }); } else { MainMenuForm
  • 16. @Override protected Container createContent() { Container c = new Container(BoxLayout.y()); final Menu m = Restaurant.getInstance().menu.get(); if(m.dishes.size() == 0) { if(DishService.hasCachedDishList()) { DishService.loadDishesFromCache(); } } if(m.dishes.size() > 0) { for(Dish currentDish : m.dishes) { c.add(createDishContainer(currentDish)); } c.addPullToRefresh(() -> { DishService.updateDishesFromServerSync(); c.removeAll(); for(Dish currentDish : m.dishes) { c.add(createDishContainer(currentDish)); } c.revalidate(); }); } else { MainMenuForm
  • 17. } else { final Container infi = FlowLayout.encloseCenter(new InfiniteProgress()); c.add(infi); m.dishDownloadFinished.addChangeListener(p -> { c.removeAll(); for(Dish currentDish : m.dishes) { c.add(createDishContainer(currentDish)); } categoryModel.removeAll(); for(String s : m.categories) { categoryModel.addItem(s); } c.revalidate(); }); } c.setScrollableY(true); c.setScrollVisible(false); dishesContainer = c; return c; } MainMenuForm