A mobile web app for Android in 75 minutes

25,580 views

Published on

AnDevCon II workshop, November 2011

Published in: Technology, Design
1 Comment
11 Likes
Statistics
Notes
No Downloads
Views
Total views
25,580
On SlideShare
0
From Embeds
0
Number of Embeds
271
Actions
Shares
0
Downloads
765
Comments
1
Likes
11
Embeds 0
No embeds

No notes for slide

A mobile web app for Android in 75 minutes

  1. 1. A Mobile Web App for Android in 75 Minutes @ jamespearce
  2. 2. Single device Multi deviceSedentary user Mobile user *Declarative ImperativeThin client Thick clientDocuments Applications * or supine, or sedentary, or passive, or...
  3. 3. A badge for all these ways the web is changing
  4. 4. WebFont Video Audio GraphicsDevice Access Camera CSS Styling & Layout Network Location HTTP JavaScript Contacts AJAX SMS Semantic HTML Events Orientation Sockets File Systems Workers & Cross-App Gyro Databases Parallel SSL Messaging App Caches Processing (all the elements of a modern application platform)
  5. 5. IntroducingSencha Touch
  6. 6. A JavaScript framework for building rich mobile apps with web standards
  7. 7. http://sencha.com/touch
  8. 8. Components Lists
  9. 9. Theming
  10. 10. Forms
  11. 11. Scrolling
  12. 12. Touch Events
  13. 13. Data access & MVC
  14. 14. Charts
  15. 15. Kitchen Sinkhttp://sencha.com/x/5e
  16. 16. Sencha Touch 2
  17. 17. Hello World
  18. 18. http://sencha.com/x/d5
  19. 19. <!DOCTYPE  html><html>    <head>            <title>Hello  World</title>        <script  src="lib/touch/sencha-­‐touch.js"></script>        <script  src="app/app.js"></script>                <link  href="lib/touch/resources/css/sencha-­‐touch.css"                      rel="stylesheet"  type="text/css"  />        </head>    <body></body></html>
  20. 20. new  Ext.Application({        launch:  function()  {                new  Ext.Panel({                        fullscreen:  true,                        dockedItems:  [{xtype:toolbar,  title:My  First  App}],                        layout:  fit,                        styleHtmlContent:  true,                        html:  <h2>Hello  World!</h2>I  did  it!                });        }});
  21. 21. Listsvar  list  =  new  Ext.List({        store:  store,        itemTpl:  {firstName}  {lastName},        grouped:  true,        indexBar:  true});
  22. 22. Nested Listsvar  list  =  new  Ext.NestedList({        store:  store,        displayField:  name,        title:  My  List,        updateTitleText:  true,        getDetailCard:                function(record,  parent)  {..}});
  23. 23. Carouselsvar  carousel  =  new  Ext.Carousel({        direction:  horizontal,        indicator:  true,        items:  [                ..        ]});
  24. 24. Common patterns 1var  list  =  new  Ext.List({        store:  store,        itemTpl:  {firstName}  {lastName},        grouped:  true,        indexBar:  true});var  panel  =  new  Ext.Panel({        fullscreen:  true,        layout:  fit,        items:  [list]});
  25. 25. Common patterns 2var  panel  =  new  Ext.Panel({        fullscreen:  true,        layout:  fit,        items:  [{                xtype:  list,                store:  store,                itemTpl:  {firstName}  {lastName},                grouped:  true,                indexBar:  true        }]});
  26. 26. A more complex app
  27. 27. Pre-requisites Sencha Touch SDK:   http://sencha.com/products/touch/  Yelp developer API key:  http://www.yelp.com/developers/getting_started/ api_overview  Install Sass and Compass:   http://sass-lang.com/download.html http://compass-style.org/install/
  28. 28. The Valley Apphttp://jamesgpearce.github.com/ValleyGuide http://sencha.com/x/e8
  29. 29. https://github.com/jamesgpearce/ValleyGuide
  30. 30. Development sequence1 Structure the app 5 Detail page2 Layout the UI 6 Add a map3 Model the data 7 Customize theme4 Load the list
  31. 31. 1 Structure the app
  32. 32. index.html<!doctype  html><html>        <head>                <title>Valley  Guide</title>        </head> <body></body></html>
  33. 33. index.html<script  src="lib/touch/sencha-­‐touch.js"></script><script  src="app/yelp.js"></script><script  src="app/app.js"></script><link  href="lib/touch/resources/css/sencha-­‐touch.css"              rel="stylesheet"  type="text/css"  />
  34. 34. app.jsvar  va  =  new  Ext.Application({        launch:  function()  {                this.viewport  =  new  Ext.Panel({                        layout:  card,                        fullscreen:  true,                        html:  "Hello  world!"                        });        }});
  35. 35. 2 Layout the UI toolbar toolbar dataList listCard detailCardva.viewport
  36. 36. The app...var  va  =  new  Ext.Application({        launch:  function()  {                this.listCard  =  new  Ext.Panel({                        html:  I  am  the  list                });                this.detailCard  =  new  Ext.Panel({                        html:  I  am  the  detail                });                this.viewport  =  new  Ext.Panel({                        layout:  card,                        fullscreen:  true,                        cardSwitchAnimation:  slide,                        items:  [this.listCard,  this.detailCard]                });        }});
  37. 37. listCardthis.listCardToolbar  =  new  Ext.Toolbar({        dock:  top,        title:  Valley  Guide});this.listCardDataList  =  new  Ext.List({        store:  null,        itemTpl:  });this.listCard  =  new  Ext.Panel({        dockedItems:  [this.listCardToolbar],        items:  [this.listCardDataList],        layout:  fit});
  38. 38. detailCardthis.detailCardToolbar  =  new  Ext.Toolbar({        dock:  top,        title:  ...});this.detailCard  =  new  Ext.Panel({        dockedItems:  [this.detailCardToolbar]});
  39. 39. 3 Model the datahttp://api.yelp.com/business_review_search?ywsid=YELP_KEY&term=Restaurants&location=Silicon%20Valley
  40. 40. Apigee console
  41. 41. "businesses":  [        {          "rating_img_url"  :  "http://media4.px.yelpcdn.com/...",          "country_code"  :  "US",          "id"  :  "BHpAlynD9dIGIaQDRqHCTA",          "is_closed"  :  false,          "city"  :  "Nashville",          "mobile_url"  :  "http://mobile.yelp.com/biz/...",          "review_count"  :  50,          "zip"  :  "11231",          "state"  :  "TN",          "latitude"  :  40.675758,          "address1"  :  "253  Conover  St",          "address2"  :  "",          "address3"  :  "",          "phone"  :  "7186258211",          "state_code"  :  "TN",          "categories":  [            ...",          ],          ...
  42. 42. A data namespacethis.data  =  {};
  43. 43. The ‘Business’ modelthis.data.Business  =  Ext.regModel(,  {        fields:  [                {name:  "id",  type:  "int"},                {name:  "name",  type:  "string"},                {name:  "latitude",  type:  "string"},                {name:  "longitude",  type:  "string"},                {name:  "address1",  type:  "string"},                {name:  "address2",  type:  "string"},                {name:  "address3",  type:  "string"},                {name:  "phone",  type:  "string"},                {name:  "state_code",  type:  "string"},                {name:  "mobile_url",  type:  "string"},                {name:  "rating_img_url_small",  type:  "string"},                {name:  "photo_url",  type:  "string"},        ]});
  44. 44. A store of those modelsthis.data.restaurants  =  new  Ext.data.Store({        model:  this.data.Business,        autoLoad:  true,        proxy:  {                type:  scripttag,                url:  http://api.yelp.com/business_review_search  +                        ?ywsid=  +  YELP_KEY  +                        &term=Restaurant  +                        &location=Silicon%20Valley,                reader:  {                        type:  json,                        root:  businesses                }        }});
  45. 45. 4 Load the listthis.listCardDataList  =  new  Ext.List({        store:  this.data.restaurants,        itemTpl:  {name}});
  46. 46. A more interesting templateitemTpl:        <img  class="photo"  src="{photo_url}"  width="40"  height="40"/>  +        {name}<br/>  +        <img  src="{rating_img_url_small}"/>&nbsp;  +        <small>{address1}</small>
  47. 47. Hack the style<style>        .photo  {                float:left;                margin:0  8px  16px  0;                border:1px  solid  #ccc;        }</style>
  48. 48. Get images resized... ...width="40"  height="40"  />
  49. 49. ...in the cloudsrc="http://src.sencha.io/40/{photo_url}"  width="40"  height="40"/>
  50. 50. 5 Detail pagethis.listCardDataList  =  new  Ext.List({        store:  this.data.restaurants,        itemTpl:  ...        listeners:  {                selectionchange:  function  (selectionModel,  records)  {                        if  (records[0])  {                                va.viewport.setActiveItem(va.detailCard);                                va.detailCardToolbar.setTitle(                                        records[0].get(name)                                );                        }                }        }});
  51. 51. List buttonthis.detailCardToolbar  =  new  Ext.Toolbar({        dock:  top,        title:  ...,        items:  [{                text:  List,                handler:  function  ()  {                        va.viewport.setActiveItem(                                va.listCard,                                {type:  slide,  direction:  right}                        );                }        }]});
  52. 52. Detail templatethis.detailCard  =  new  Ext.Panel({        dockedItems:  [this.detailCardToolbar],        styleHtmlContent:  true,        cls:  detail,        tpl:  [                <img  class="photo"  src="{photo_url}"                            width="100"  height="100"/>,                <h2>{name}</h2>,                <div  class="info">,                        {address1}<br/>,                        <img  src="{rating_img_url_small}"/>,                </div>,                <div  class="phone  x-­‐button">,                        <a  href="tel:{phone}">{phone}</a>,                </div>,                <div  class="link  x-­‐button">,                        <a  href="{mobile_url}">Read  more</a>,                </div>        ]});
  53. 53. A little styling.x-­‐html  h2  {        margin-­‐bottom:0;}.phone,  .link  {        clear:both;        font-­‐weight:bold;        display:block;        text-­‐align:center;        margin-­‐top:8px;}
  54. 54. 6 Add a map toolbar toolbar dataList dataList detailCard listCard detailTabsva.viewport
  55. 55. 6 Add a mapva.viewport.setActiveItem(va.detailTabs);...this.detailMap  =  new  Ext.Map({});this.detailTabs  =  new  Ext.TabPanel({        dockedItems:  [this.detailCardToolbar],        items:  [this.detailCard,  this.detailMap]});va.viewport  =  new  Ext.Panel({        layout:  card,        fullscreen:  true,        cardSwitchAnimation:  slide,        items:  [this.listCard,  this.detailTabs]});
  56. 56. Tab titlesthis.detailCard  =  new  Ext.Panel({        ...        title:  Info});this.detailMap  =  new  Ext.Map({        title:  Map});
  57. 57. Google Maps script<script  type="text/javascript"    src="http://maps.google.com/maps/api/js?sensor=true"></script>
  58. 58. Update the map locationselectionchange:  function  (selectionModel,  records)  {        ...        var  map  =  va.detailMap.map;        if  (!map.marker)  {                map.marker  =  new  google.maps.Marker();                map.marker.setMap(map);        }        map.setCenter(                new  google.maps.LatLng(                        records[0].get(latitude),                        records[0].get(longitude)                )        );        map.marker.setPosition(                map.getCenter()        );
  59. 59. Improve the tab barthis.detailTabs  =  new  Ext.TabPanel({        dockedItems:  [this.detailCardToolbar],        items:  [this.detailCard,  this.detailMap],        tabBar:  {                ui:  light,                layout:  {  pack:  center  }        }});
  60. 60. 7 Customize theme
  61. 61. http://sass-lang.com/
  62. 62. Variables/* SCSS */ /* CSS */$blue: #3bbfce; .content-navigation {$margin: 16px; border-color: #3bbfce; color: #2b9eab;.content-navigation { } border-color: $blue; color: .border { darken($blue, 9%); padding: 8px;} margin: 8px; border-color: #3bbfce;.border { } padding: $margin / 2; margin: $margin / 2; border-color: $blue;}
  63. 63. $> sudo gem install compass http://rubyinstaller.org/
  64. 64. $> compass -vCompass 0.11.1 (Antares)Copyright (c) 2008-2011 Chris EppsteinReleased under the MIT License.$> sass -vSass 3.1.1 (Brainy Betty)
  65. 65. Start by copying sencha-touch.scss
  66. 66. config.rbdir  =  File.dirname(__FILE__)load  File.join(dir,  themes)#  Compass  configurationssass_path        =  dircss_path          =  direnvironment    =  :productionoutput_style  =  :compressed#  or  :nested,  :expanded,  :compact
  67. 67. Compile...$>  cd  theming$>  compass  compile  valley.scss            create  valley.css$>  compass  compile  valley.scss            identical  valley.css[edit  file]$>  compass  compile  valley.scss            overwrite  valley.css$>  compass  watch  valley.scss            >>>  Change  detected  to:  valley.scss            overwrite  valley.css
  68. 68. Link...<link  href="theming/valley.css"  rel="stylesheet"            type="text/css"  />
  69. 69. valley.scss@import  sencha-­‐touch/default/all;@include  sencha-­‐panel;@include  sencha-­‐buttons;@include  sencha-­‐sheet;@include  sencha-­‐tabs;@include  sencha-­‐toolbar;@include  sencha-­‐list;@include  sencha-­‐list-­‐pullrefresh;@include  sencha-­‐layout;@include  sencha-­‐loading-­‐spinner;...
  70. 70. valley.scss$base-­‐color:  #9D9E00;$base-­‐gradient:  none;$include-­‐default-­‐icons:  false;$include-­‐border-­‐radius:  false;@import  sencha-­‐touch/default/all;@include  sencha-­‐panel;@include  sencha-­‐buttons;@include  sencha-­‐sheet;@include  sencha-­‐tabs;@include  sencha-­‐toolbar;@include  sencha-­‐list;@include  sencha-­‐list-­‐pullrefresh;@include  sencha-­‐layout;@include  sencha-­‐loading-­‐spinner;
  71. 71. Choose own icons$base-­‐color:  #9D9E00;$include-­‐default-­‐icons:  false;@import  sencha-­‐touch/default/all;@include  sencha-­‐panel;@include  sencha-­‐buttons;...@include  pictos-­‐iconmask(briefcase1);@include  pictos-­‐iconmask(heart);@include  pictos-­‐iconmask(music1);
  72. 72. http://dev.sencha.com/deploy/touch/docs/theme/
  73. 73. Sass is a superset of CSS$base-­‐color:  #9D9E00;$include-­‐default-­‐icons:  false;@import  sencha-­‐touch/default/all;....photo  {        float:left;        margin:0  8px  16px  0;        border:1px  solid  #ccc;}...
  74. 74. Done?
  75. 75. Development sequence1 Structure the app 5 Detail page2 Layout the UI 6 Add a map3 Model the data 7 Customize theme4 Load the list
  76. 76. A ‘responsive’ app...http://sencha.com/x/cv
  77. 77. And if we’d had time... Add to home screen - Icon - Splash screen Hybrid app with device APIs http://sencha.com/x/cy http://sencha.com/x/de
  78. 78. O ine app$>  phantomjs  confess.js  http://github/valley/CACHE  MANIFEST#  This  manifest  was  created  by  confess.js#                    Time:  Wed  Sep  14  2011  10:14:45  GMT-­‐0700  (PDT)#        User-­‐agent:  Mozilla/5.0  ...CACHE:app/app.jsapp/yelp.jshttp://cdn.sencha.io/touch/1.1.0/sencha-­‐touch.jshttp://maps.google.com/maps/api/js?sensor=truehttp://maps.gstatic.com/intl/en_us/mapfiles/api-­‐3/6/4/main.jstheming/valley.cssNETWORK:*http://github.com/jamesgpearce/confess
  79. 79. O ine dataTaking Yelp data o ineTaking images o ine- src.sencha.io to generate cross-origin B64Detecting network connection changeshttp://sencha.com/x/df
  80. 80. Weinrehttp://phonegap.github.com/weinre
  81. 81. built withApps vs Web technology
  82. 82. James Pearce@ jamespearce

×