Shai Almog [email protected] Co-founder & CEO of Codename One JavaOne Rockstar, DZone MVB, JavaZone top speaker… Worked on mobile development tools since the 90’s at Sun Member of original WTK team, co-creator of LWUIT project Worked with Sun/Oracle, IBM, DoCoMo, Nokia, Samsung, Verizon, Sprint, Vodafone, Sony Ericsson and more Open source hacker, Java developer since 96 Over 20 years of professional software development experience
One • Open source - Java for all devices • Supports iOS, Android & Windows Phone • Integrates with Eclipse, NetBeans & IntelliJ • GUI builder, theme editor, localization tools • API abstracting device • Designed for Tablets/Phones • Cloud based compilation
is in the Codename One SVN here: http://code.google.com/p/codenameone/source/ browse/trunk/Demos/ Don’t worry if you can’t follow or forget something… Everything will be posted in the Codename One blog after the conference!
Point public void start() { if(current != null){ current.show(); return; } Form hi = new Form("Hi World"); hi.addComponent(new Label("Hi World")); hi.show(); }
Point public void start() { if(current != null){ current.show(); return; } Form hi = new Form("Hi World"); hi.addComponent(new Label("Hi World")); hi.show(); } We have a component- container hierarchy Form is top level component
Point public void start() { if(current != null){ current.show(); return; } Form hi = new Form("Hi World"); hi.addComponent(new Label("Hi World")); hi.show(); } We have a component- container hierarchy Form is top level component
Method Form hi = new Form("Welcome"); BorderLayout bl = new BorderLayout(); bl.setCenterBehavior(BorderLayout.CENTER_BEHAVIOR_CENTER); hi.setLayout(bl); hi.setFormBottomPaddingEditingMode(true); ComponentGroup cg = new ComponentGroup(); final TextField name = new TextField(); name.setHint("What Is Your Name?"); final Button btn = new Button("Take Photo"); cg.addComponent(name); cg.addComponent(btn); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { userPicture = captureRoundImage(); btn.setIcon(userPicture); } }); hi.addComponent(BorderLayout.CENTER, cg); Toolbar t = new Toolbar(); hi.setToolBar(t); t.addCommandToRightBar(new Command("Next") { @Override public void actionPerformed(ActionEvent evt) { userName = name.getText(); if(userName.length() == 0) { userName = "[Unnamed]"; } showSbaitso(); } }); hi.show(); The component group creates the rounded edges Action listener is invoked when the button is clicked Next moves to the next form which is the main app form
Method Form hi = new Form("Welcome"); BorderLayout bl = new BorderLayout(); bl.setCenterBehavior(BorderLayout.CENTER_BEHAVIOR_CENTER); hi.setLayout(bl); hi.setFormBottomPaddingEditingMode(true); ComponentGroup cg = new ComponentGroup(); final TextField name = new TextField(); name.setHint("What Is Your Name?"); final Button btn = new Button("Take Photo"); cg.addComponent(name); cg.addComponent(btn); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { userPicture = captureRoundImage(); btn.setIcon(userPicture); } }); hi.addComponent(BorderLayout.CENTER, cg); Toolbar t = new Toolbar(); hi.setToolBar(t); t.addCommandToRightBar(new Command("Next") { @Override public void actionPerformed(ActionEvent evt) { userName = name.getText(); if(userName.length() == 0) { userName = "[Unnamed]"; } showSbaitso(); } }); hi.show(); The component group creates the rounded edges Action listener is invoked when the button is clicked Next moves to the next form which is the main app form
result) { try { int width = Display.getInstance().getDisplayWidth(); Image capturedImage = Image.createImage(Capture.capturePhoto(width, -1)); Image roundMask = Image.createImage(width, capturedImage.getHeight(), 0xff000000); Graphics gr = roundMask.getGraphics(); gr.setColor(0xffffff); gr.fillArc(0, 0, width, width, 0, 360); Object mask = roundMask.createMask(); capturedImage = capturedImage.applyMask(mask); result.setIcon(capturedImage); } catch(IOException err) { err.printStackTrace(); } } Creating A Picture (Avatar) Capture a picture at device width with aspect ratio Create an image we can modify into a mask Apply the mask to the captured image and set to label
result) { try { int width = Display.getInstance().getDisplayWidth(); Image capturedImage = Image.createImage(Capture.capturePhoto(width, -1)); Image roundMask = Image.createImage(width, capturedImage.getHeight(), 0xff000000); Graphics gr = roundMask.getGraphics(); gr.setColor(0xffffff); gr.fillArc(0, 0, width, width, 0, 360); Object mask = roundMask.createMask(); capturedImage = capturedImage.applyMask(mask); result.setIcon(capturedImage); } catch(IOException err) { err.printStackTrace(); } } Creating A Picture (Avatar) Capture a picture at device width with aspect ratio Create an image we can modify into a mask Apply the mask to the captured image and set to label
Form sb = new Form(); sb.setFormBottomPaddingEditingMode(true); Toolbar t = new Toolbar(); sb.setToolBar(t); final TextField searchField = new TextField(); searchField.setHint("Search For Answers..."); t.setTitleComponent(searchField); sb.setLayout(new BorderLayout()); final TextField ask = new TextField(); ask.setHint("Ask The Dr."); Container askContainer = new Container(new BorderLayout()); askContainer.addComponent(BorderLayout.CENTER, ask); Button askButton = new Button("Ask"); askContainer.addComponent(BorderLayout.EAST, askButton); sb.addComponent(BorderLayout.SOUTH, askContainer); final Container discussion = new Container(new BoxLayout(BoxLayout.Y_AXIS)); sb.addComponent(BorderLayout.CENTER, discussion); discussion.setScrollableY(true); sb.show(); The Main UI (part I)
Form sb = new Form(); sb.setFormBottomPaddingEditingMode(true); Toolbar t = new Toolbar(); sb.setToolBar(t); final TextField searchField = new TextField(); searchField.setHint("Search For Answers..."); t.setTitleComponent(searchField); sb.setLayout(new BorderLayout()); final TextField ask = new TextField(); ask.setHint("Ask The Dr."); Container askContainer = new Container(new BorderLayout()); askContainer.addComponent(BorderLayout.CENTER, ask); Button askButton = new Button("Ask"); askContainer.addComponent(BorderLayout.EAST, askButton); sb.addComponent(BorderLayout.SOUTH, askContainer); final Container discussion = new Container(new BoxLayout(BoxLayout.Y_AXIS)); sb.addComponent(BorderLayout.CENTER, discussion); discussion.setScrollableY(true); sb.show(); The Main UI (part I) Main chat window allows searching the discussion Questions/ Answers are placed in a box layout Y Notice the ask text field and ask button share a container
public void run() { say(discussion, "HELLO " + userName +", MY NAME IS DOCTOR SBAITSO. \n\nI AM HERE TO HELP YOU.\n" + "SAY WHATEVER IS IN YOUR MIND FREELY," + "OUR CONVERSATION WILL BE KEPT IN STRICT CONFIDENCE.\n" + "MEMORY CONTENTS WILL BE WIPED OFF AFTER YOU LEAVE.", false); } }); searchField.addDataChangeListener(createSearchListener(searchField, discussion, askButton)); ActionListener askEvent = new ActionListener() { public void actionPerformed(ActionEvent evt) { String t = ask.getText(); if(t.length() > 0) { ask.setText(""); say(discussion, t, true); answer(t, discussion); } } }; ask.setDoneListener(askEvent); askButton.addActionListener(askEvent); } The Main UI (part II)
public void run() { say(discussion, "HELLO " + userName +", MY NAME IS DOCTOR SBAITSO. \n\nI AM HERE TO HELP YOU.\n" + "SAY WHATEVER IS IN YOUR MIND FREELY," + "OUR CONVERSATION WILL BE KEPT IN STRICT CONFIDENCE.\n" + "MEMORY CONTENTS WILL BE WIPED OFF AFTER YOU LEAVE.", false); } }); searchField.addDataChangeListener(createSearchListener(searchField, discussion, askButton)); ActionListener askEvent = new ActionListener() { public void actionPerformed(ActionEvent evt) { String t = ask.getText(); if(t.length() > 0) { ask.setText(""); say(discussion, t, true); answer(t, discussion); } } }; ask.setDoneListener(askEvent); askButton.addActionListener(askEvent); } The Main UI (part II) We ask/ answer using the “say” method CallSerially postpones the question to the next cycle of the EDT We use data change for the search but done for ask
public void run() { say(discussion, "HELLO " + userName +", MY NAME IS DOCTOR SBAITSO. \n\nI AM HERE TO HELP YOU.\n" + "SAY WHATEVER IS IN YOUR MIND FREELY," + "OUR CONVERSATION WILL BE KEPT IN STRICT CONFIDENCE.\n" + "MEMORY CONTENTS WILL BE WIPED OFF AFTER YOU LEAVE.", false); } }); searchField.addDataChangeListener(createSearchListener(searchField, discussion, askButton)); ActionListener askEvent = new ActionListener() { public void actionPerformed(ActionEvent evt) { String t = ask.getText(); if(t.length() > 0) { ask.setText(""); say(discussion, t, true); answer(t, discussion); } } }; ask.setDoneListener(askEvent); askButton.addActionListener(askEvent); } The Main UI (part II) We ask/ answer using the “say” method CallSerially postpones the question to the next cycle of the EDT We use data change for the search but done for ask
Container dest) { say(dest, AI.getResponse(question), false); } void say(Container destination, String text, boolean question) { SpanLabel t = new SpanLabel(text); t.setWidth(destination.getWidth()); t.setX(0); t.setHeight(t.getPreferredH()); if(question) { t.setY(Display.getInstance().getDisplayHeight()); t.setTextUIID("BubbleUser"); t.setIconPosition(BorderLayout.EAST); t.setIcon(userPicture); t.setTextBlockAlign(Component.RIGHT); } else { t.setY(0); t.setTextUIID("BubbleSbaitso"); t.setTextBlockAlign(Component.LEFT); } destination.addComponent(t); destination.animateLayoutAndWait(400); destination.scrollComponentToVisible(t); } Say & Answer Answer is just a convenience call to say Say just creates and styles a label notice the set UIID… After changing the UI we animate it into place
Container dest) { say(dest, AI.getResponse(question), false); } void say(Container destination, String text, boolean question) { SpanLabel t = new SpanLabel(text); t.setWidth(destination.getWidth()); t.setX(0); t.setHeight(t.getPreferredH()); if(question) { t.setY(Display.getInstance().getDisplayHeight()); t.setTextUIID("BubbleUser"); t.setIconPosition(BorderLayout.EAST); t.setIcon(userPicture); t.setTextBlockAlign(Component.RIGHT); } else { t.setY(0); t.setTextUIID("BubbleSbaitso"); t.setTextBlockAlign(Component.LEFT); } destination.addComponent(t); destination.animateLayoutAndWait(400); destination.scrollComponentToVisible(t); } Say & Answer Answer is just a convenience call to say Say just creates and styles a label notice the set UIID… After changing the UI we animate it into place
Further Reading How Do I - codenameone.com/how-do-i.html Source code for Dr. Sbaitso - code.google.com/p/codenameone/source/browse/trunk/Demos Developer Guide - codenameone.com/developer-guide.html Discussion Forum - www.codenameone.com/discussion-forum.html Course (free for pro users) - udemy.com/codenameone101/ Source code/Issue tracker -code.google.com/p/codenameone/ JavaDocs - codenameone.googlecode.com/svn/trunk/CodenameOne/javadoc/index.html Blog - codenameone.com/blog Shai Almog @Codename_One http://www.codenameone.com/