Weitere ähnliche Inhalte Ähnlich wie A mobile web app for Android in 75 minutes (20) Mehr von James Pearce (19) Kürzlich hochgeladen (20) A mobile web app for Android in 75 minutes2. Single device Multi device
Sedentary user Mobile user
*
Declarative Imperative
Thin client Thick client
Documents Applications
* or supine, or sedentary, or passive, or...
4. WebFont Video Audio Graphics
Device 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)
20. <!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>
21. 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!'
});
}
});
23. Lists
var
list
=
new
Ext.List({
store:
store,
itemTpl:
'{firstName}
{lastName}',
grouped:
true,
indexBar:
true
});
24. Nested Lists
var
list
=
new
Ext.NestedList({
store:
store,
displayField:
'name',
title:
'My
List',
updateTitleText:
true,
getDetailCard:
function(record,
parent)
{..}
});
26. Common patterns
1
var
list
=
new
Ext.List({
store:
store,
itemTpl:
'{firstName}
{lastName}',
grouped:
true,
indexBar:
true
});
var
panel
=
new
Ext.Panel({
fullscreen:
true,
layout:
'fit',
items:
[list]
});
27. Common patterns
2
var
panel
=
new
Ext.Panel({
fullscreen:
true,
layout:
'fit',
items:
[{
xtype:
'list',
store:
store,
itemTpl:
'{firstName}
{lastName}',
grouped:
true,
indexBar:
true
}]
});
29. 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/
36. app.js
var
va
=
new
Ext.Application({
launch:
function()
{
this.viewport
=
new
Ext.Panel({
layout:
'card',
fullscreen:
true,
html:
"Hello
world!"
});
}
});
37. 2 Layout the UI
toolbar toolbar
dataList
listCard detailCard
va.viewport
38. 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]
});
}
});
39. listCard
this.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'
});
41. 3 Model the data
http://api.yelp.com/business_review_search
?ywsid=YELP_KEY
&term=Restaurants
&location=Silicon%20Valley
44. "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":
[
...",
],
...
46. The ‘Business’ model
this.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"},
]
});
47. A store of those models
this.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'
}
}
});
48. 4 Load the list
this.listCardDataList
=
new
Ext.List({
store:
this.data.restaurants,
itemTpl:
'{name}'
});
49. 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>'
53. 5 Detail page
this.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')
);
}
}
}
});
54. List button
this.detailCardToolbar
=
new
Ext.Toolbar({
dock:
'top',
title:
'...',
items:
[{
text:
'List',
handler:
function
()
{
va.viewport.setActiveItem(
va.listCard,
{type:
'slide',
direction:
'right'}
);
}
}]
});
55. Detail template
this.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>'
]
});
56. A little styling
.x-‐html
h2
{
margin-‐bottom:0;
}
.phone,
.link
{
clear:both;
font-‐weight:bold;
display:block;
text-‐align:center;
margin-‐top:8px;
}
57. 6 Add a map
toolbar toolbar
dataList dataList
detailCard
listCard detailTabs
va.viewport
58. 6 Add a map
va.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]
});
61. Update the map location
selectionchange:
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()
);
62. Improve the tab bar
this.detailTabs
=
new
Ext.TabPanel({
dockedItems:
[this.detailCardToolbar],
items:
[this.detailCard,
this.detailMap],
tabBar:
{
ui:
'light',
layout:
{
pack:
'center'
}
}
});
65. 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;
}
66. $> sudo gem install compass
http://rubyinstaller.org/
67. $> compass -v
Compass 0.11.1 (Antares)
Copyright (c) 2008-2011 Chris Eppstein
Released under the MIT License.
$> sass -v
Sass 3.1.1 (Brainy Betty)
69. config.rb
dir
=
File.dirname(__FILE__)
load
File.join(dir,
'themes')
#
Compass
configurations
sass_path
=
dir
css_path
=
dir
environment
=
:production
output_style
=
:compressed
#
or
:nested,
:expanded,
:compact
70. 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
75. 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');
77. 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;
}
...
81. 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
82. 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.js
app/yelp.js
http://cdn.sencha.io/touch/1.1.0/sencha-‐touch.js
http://maps.google.com/maps/api/js?sensor=true
http://maps.gstatic.com/intl/en_us/mapfiles/api-‐3/6/4/main.js
theming/valley.css
NETWORK:
*
http://github.com/jamesgpearce/confess
83. 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