The City Bars App with Sencha Touch 2
-
Upload
james-pearce -
Category
Technology
-
view
14.104 -
download
1
description
Transcript of The City Bars App with Sencha Touch 2
![Page 1: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/1.jpg)
The City Bars Appwith
Sencha Touch 2
![Page 2: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/2.jpg)
A JavaScript framework for building rich mobile apps with web standards
Sencha Touch
![Page 3: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/3.jpg)
http://sencha.com/x/d5http://sencha.com/x/ed
![Page 4: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/4.jpg)
Basically...
Get a WebKit-based desktop browser
Get some emulators & real devices
Download the Sencha Touch 2 PR2 SDK
Develop against a local web server
Optional, but highly recommended!
![Page 5: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/5.jpg)
![Page 6: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/6.jpg)
![Page 7: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/7.jpg)
http://sencha.com/touch
![Page 8: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/8.jpg)
stylesheet
script framework
![Page 9: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/9.jpg)
Introducing theCity Bars App
![Page 10: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/10.jpg)
![Page 11: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/11.jpg)
![Page 12: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/12.jpg)
http://senchalearn.github.com/citybars2
http://sencha.com/x/ee
![Page 13: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/13.jpg)
Pre-requisites
Yelp developer API key: http://www.yelp.com/developers/
Install Sass and Compass: http://sass-lang.com/download.html
http://compass-style.org/install/
![Page 14: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/14.jpg)
http://github.com/senchalearn/citybars2
![Page 15: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/15.jpg)
Development sequence
1 App Architecture
2 UI Structure
3 Data Modeling
4 List Binding
5 List Event Handler
6 Detail Page
7 Customize Theme
![Page 16: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/16.jpg)
![Page 17: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/17.jpg)
Application Architecture
1_app_architecture
![Page 18: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/18.jpg)
application
JS + CSS in SDK
entry point
![Page 19: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/19.jpg)
<!doctype html><html> <head>
<title>City Guide</title>
<script src="lib/touch2/sencha-‐touch-‐all-‐debug.js"></script> <link href="lib/touch2/resources/css/sencha-‐touch.css" rel="stylesheet" />
<script src="app/app.js"></script>
</head> <body></body></html>
index.html
our app
don’t panic
JS + CSS*
*or from CDN
yay! HTML5
![Page 20: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/20.jpg)
var CB;Ext.application({
launch: function() { CB = this; CB.cards = Ext.create('Ext.Panel', { fullscreen: true, html: 'Hello world' }); }
});config object
global namespace
instantiates application
create main UI panel
launch event
app.js
![Page 21: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/21.jpg)
![Page 22: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/22.jpg)
![Page 23: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/23.jpg)
UI Structure
2_ui_structure
![Page 24: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/24.jpg)
CB.cards
listCard detailCard
toolbar toolbar
dataList
click
back
![Page 25: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/25.jpg)
var CB;Ext.application({
launch: function() { CB = this; CB.cards = Ext.create('Ext.Panel', { fullscreen: true, layout: 'card', items: [{ id: 'listCard', html: 'List' }, { id: 'detailCard', html: 'Detail' }] }); }
});
id-based ref
UI children
variable ref
how children lay out
![Page 26: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/26.jpg)
![Page 27: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/27.jpg)
<aside>about layouts
and components
![Page 28: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/28.jpg)
Layoutscard
fit hbox
vbox
![Page 29: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/29.jpg)
Child component patterns I
var list = new Ext.List({ store: store, ...});
var panel = new Ext.Panel({ items: [list, ...], ...});
reference component by var
instantiate component
![Page 30: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/30.jpg)
Child component patterns II
var list = Ext.create('Ext.List', { store: store, ...});
var panel = Ext.create('Ext.Panel', { items: [list, ...] ...});
preferable in ST2
![Page 31: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/31.jpg)
Child component patterns III
var panel = Ext.create('Ext.Panel', { items: [ { xtype: 'list', store: store, ... }, ... ], ...});
deferred creation*
* a lightweight object until then
![Page 32: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/32.jpg)
</aside>
![Page 33: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/33.jpg)
{ // the list card id: 'listCard', layout: 'fit', items: [{ // main top toolbar xtype: 'toolbar', docked: 'top', title: 'Please wait' // will get added once city known }, { // the list itself // gets bound to the store once city known id: 'dataList', xtype: 'list' }]}
* list will be bound to a store later
list*
The list card
list should fill whole card
docked top toolbar
![Page 34: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/34.jpg)
{ // the details card id: 'detailCard', items: [{ // detail page also has a toolbar docked : 'top', xtype: 'toolbar', title: '' }, { // textual detail }]}
detail page to come later...
The detail card
another docked toolbar*
* title will be dynamically set
![Page 35: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/35.jpg)
note:list already
scrollable
![Page 36: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/36.jpg)
Data modeling
3_data_modeling
![Page 37: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/37.jpg)
http://api.yelp.com/business_review_search
?ywsid=YELP_KEY
&term=BUSINESS_TYPE
&location=CITY
The YELP API...
free, rate limited
business type, and city name
![Page 38: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/38.jpg)
...returns a nested JSON array
mmm, json
![Page 39: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/39.jpg)
‘businesses’ array
Apigee API console
![Page 40: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/40.jpg)
"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": [...], ... }, ...]
some fields areuseful for our app
![Page 41: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/41.jpg)
Ext.define("Business", { extend: "Ext.data.Model", 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"}, ]});
give the ‘class’ a name
Create a data model
extending base model
and with these named, typed fields
![Page 42: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/42.jpg)
<aside>
</aside>
Models can be associated
with other models
Fields can also have default values,
conversion functions, and validation
![Page 43: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/43.jpg)
var store = Ext.create('Ext.data.Store', { model: "Business", ...});
Create a model store
Think of a store as a ‘table’ of model instance ‘rows’
create the store
containing thistype of model
![Page 44: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/44.jpg)
var store = Ext.create('Ext.data.Store', { model: 'Business', autoLoad: true, proxy: { // call Yelp to get business data type: 'scripttag', url: 'http://api.yelp.com/business_review_search' + '?ywsid=' + YELP_KEY + '&term=' + escape(BUSINESS_TYPE) + '&location=' + escape(DEFAULT_CITY) , reader: { type: 'json', root: 'businesses' } }});
Configure data sourceloads as soon as possible
construct API URL
source
read array from inside JSON
JSONP
![Page 45: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/45.jpg)
<script> YELP_KEY = 'G3HueY_I5a8WZX-‐_bAAAA'; DEFAULT_CITY = 'San Francisco'; BUSINESS_TYPE = 'Bars';</script>
Create constants
please change this!
![Page 46: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/46.jpg)
We can make the proxy URL dynamic,
which would allow geolocation.
But this requires an async
callback sequence.
![Page 47: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/47.jpg)
getCity: function (callback) { callback(DEFAULT_CITY); // this could now be a geo lookup to // get the nearest city},
getBusinesses: function (city, callback) {
Ext.define("Business", { ... }); var store = Ext.create('Ext.data.Store', { ... });
}
Two-phase async sequence
and this will need to fire the callback with store when it autoloads
the data codewe just wrote
use this in the URL
call whenUI ready
![Page 48: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/48.jpg)
var store = Ext.create('Ext.data.Store', { ... listeners: { // when the records load, fire the callback load: function (store) { callback(store); } }}); fire the callback with store
when loaded
eventlisteners
![Page 49: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/49.jpg)
store
records
cheeky callback
![Page 50: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/50.jpg)
List Binding
4_list_binding
![Page 51: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/51.jpg)
// get the cityCB.getCity(function (city) {
// then use Yelp to get the businesses CB.getBusinesses(city, function (store) {
// then bind data to list and show it CB.cards.query('#dataList')[0].setStore(store);
});});
bind the store to itget dataList by its id
our 2 async functions
![Page 52: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/52.jpg)
but we haz records!
:-(
![Page 53: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/53.jpg)
CB.getCity(function (city) {
cards.query('#listCard toolbar')[0] .setTitle(city + ' ' + BUSINESS_TYPE);
...
now title will always match city
another component query
![Page 54: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/54.jpg)
{ id: 'dataList', xtype: 'list', store: null, itemTpl: '{name}'}
model fields in curly braces
List items are templated
![Page 55: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/55.jpg)
Ext.create('Ext.LoadMask', Ext.getBody(), { store: store, msg: ''});
instantiate mask
Spinner bound to store
over body
will show when store is loading
![Page 56: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/56.jpg)
![Page 57: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/57.jpg)
A more interesting template
itemTpl: '<img class="photo" src="{photo_url}" width="40" height="40"/>' + '{name}<br/>' + '<img src="{rating_img_url_small}"/> ' + '<small>{address1}</small>'
HTML allowed
![Page 58: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/58.jpg)
<style> .photo { float:left; margin:0 8px 16px 0; border:1px solid #ccc; -‐webkit-‐box-‐shadow: 0 2px 4px #777; }</style>
Hack the style
![Page 59: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/59.jpg)
...width="40" height="40" />
seems likea waste
![Page 60: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/60.jpg)
src.sencha.io<img src="http://src.sencha.io/40/{photo_url}" width="40" height="40"/>
4 times smaller
![Page 61: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/61.jpg)
List Event Handler
5_list_event_handler
![Page 62: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/62.jpg)
{ id: 'dataList', ... listeners: { selectionchange: function (selectionModel, records) { // if selection made, slide to detail card if (records[0]) {
CB.cards.setActiveItem(1);
CB.cards.getActiveItem().setData( records[0].data );
} } }}
when list itemsare selected
selection
also fires on deselection
detail card
apply record data...
...to detail page template
![Page 63: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/63.jpg)
A back button
items: [{ // detail page also has a toolbar docked : 'top', xtype: 'toolbar', title: '', items: [{ // containing a back button // that slides back to list card text: 'Back', ui: 'back', listeners: { tap: function () { CB.cards.setActiveItem(0); } } }], ...
back to list
when tapped
arrow style
children of toolbarsare implicitlyxtype: ‘button’
![Page 64: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/64.jpg)
![Page 65: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/65.jpg)
Detail Page
6_detail_page
![Page 66: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/66.jpg)
{ // textual detail styleHtmlContent: true, cls: 'detail', tpl: [ '<img class="photo" src="{photo_url}" />', '<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>' ]}]
style this card as regular HTML
CSS class for styling
template fora whole panel
![Page 67: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/67.jpg)
:-(
![Page 68: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/68.jpg)
CB.cards.getActiveItem().setData( records[0].data);
setData does not cascade into child items!
Remember this?
![Page 69: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/69.jpg)
setData: function (data) { this.query('toolbar')[0].setTitle(data.name); this.query('[cls="detail"]')[0].setData(data);},
set title on toolbar
Override setData
apply data to template on inner panel
![Page 70: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/70.jpg)
good
not so much
![Page 71: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/71.jpg)
A little styling
.x-‐html h2 { margin-‐bottom:0;}.phone, .link { clear:both; font-‐weight:bold; display:block; text-‐align:center; margin-‐top:8px;}
.detail { -‐webkit-‐box-‐orient: vertical;}.detail .photo { float:none;}
formattingthe buttons
temporaryfixes
![Page 72: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/72.jpg)
![Page 73: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/73.jpg)
One final tweak
{ // textual detail cls: 'detail', styleHtmlContent: true, ...
...to outer card
move frominner panel...
{ // the details card id: 'detailCard', styleHtmlContent: true,
![Page 74: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/74.jpg)
complete with<h2> </h2>
![Page 75: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/75.jpg)
![Page 76: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/76.jpg)
![Page 77: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/77.jpg)
Development sequence
1 App Architecture
2 UI Structure
3 Data Modeling
4 List Binding
5 List Event Handler
6 Detail Page
7 Customize Theme
![Page 78: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/78.jpg)
Other ideas...
![Page 79: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/79.jpg)
‘Responsive’ Apps
http://sencha.com/x/cv
![Page 80: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/80.jpg)
Packaging
Add to home screen - Icon - Splash screen
Hybrid app; PhoneGap / NimbleKit - Contacts API - Geolocation
http://sencha.com/x/cyhttp://sencha.com/x/de
![Page 81: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/81.jpg)
Geolocation
![Page 82: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/82.jpg)
O!ine app
http://github.com/jamesgpearce/confess
![Page 83: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/83.jpg)
O!ine data
Taking Yelp data o"ine
Taking images o"ine - src.sencha.io to generate cross-origin B64
Detecting network connection changes
http://sencha.com/x/df
![Page 84: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/84.jpg)
Debugging
http://phonegap.github.com/weinre
![Page 85: The City Bars App with Sencha Touch 2](https://reader036.fdocuments.net/reader036/viewer/2022062404/553bb180550346e0478b45e7/html5/thumbnails/85.jpg)
James Pearce @ jamespearce