Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Cross-Platform Mobile Development

96 Articles
article-image-styling-user-interface
Packt
22 Nov 2013
8 min read
Save for later

Styling the User Interface

Packt
22 Nov 2013
8 min read
(For more resources related to this topic, see here.) Styling components versus themes Before we get into this article, it's important to have a good understanding of the difference between styling an individual component and creating a theme. Almost every display component in Sencha Touch has the option to set its own style. For example, a panel component can use a style in this way: { xtype: 'panel', style: 'border: none; font: 12px Arial black', html: 'Hello World' } The style can also be set as an object using: { xtype: 'panel', style : { 'border' : 'none', 'font' : '12px Arial black', 'border-left': '1px solid black' } html: 'Hello World' } You will notice that inside the style block, we have quoted both sides of the configuration setting. This is still the correct syntax for JavaScript and a very good habit to get in to for using style blocks. This is because a number of standard CSS styles use a dash as part of their name. If we do not add quotes to border-left, JavaScript will read this as border minus left and promptly collapse in a pile of errors. We can also set a style class for a component and use an external CSS file to define the class as follows: { xtype: 'panel', cls: 'myStyle', html: 'Hello World' } Your external CSS file could then control the style of the component in the following manner: .myStyle { border: none; font: 12px Arial black; } This class-based control of display is considered a best practice as it separates the style logic from the display logic. This means that when you need to change a border color, it can be done in one file instead of hunting through multiple files for individual style settings. These styling options are very useful for controlling the display of individual components. There are also certain style elements, such as border, padding, and margin, that can be set directly in the components' configuration: { xtype: 'panel', bodyMargin: '10 5 5 5', bodyBorder: '1px solid black', bodyPadding: 5, html: 'Hello World' } These configurations can accept either a number to be applied to all sides or a CSS string value, such as 1px solid black or 10 5 5 5. The number should be entered without quotes but the CSS string values need to be within quotes. These kind of small changes can be helpful in styling your application, but what if you need to do something a bit bigger? What if you want to change the color or appearance of the entire application? What if you want to create your own default style for your buttons? This is where themes and UI styles come into play. UI styling for toolbars and buttons Let's do a quick review of the basic MVC application we created, Creating a Simple Application, and use it to start our exploration of styles with toolbars and buttons. To begin, we are going to add a few things to the first panel, which has our titlebar, toolbar, and Hello World text. Adding the toolbar In app/views, you'll find Main.js. Go ahead and open that in your editor and takea look at the first panel in our items list: items: [ { title: 'Hello', iconCls: 'home', xtype: 'panel', html: 'Hello World', items: [ { xtype: 'titlebar', docked: 'top', title: 'About TouchStart' } ] }... We're going to add a second toolbar on top of the existing one. Locate the items section, and after the curly braces for our first toolbar, add the second toolbar in the following manner: { xtype: 'titlebar', docked: 'top', title: 'About TouchStart' }, { docked: 'top', xtype: 'toolbar', items: [ {text: 'My Button'} ]} Don't forget to add a comma between the two toolbars. Extra or missing commas While working in Sencha Touch, one of the most common causes of parse errors is an extra or missing comma. When you are moving the code around, always make sure you have accounted for any stray or missing commas. Fortunately for us, the Safari Error Console will usually give us a pretty good idea about the line number to look at for these types of parse errors. A more detailed list of common errors can be found at: http://javascript.about.com/od/reference/a/error.htm Now when you take a look at the first tab, you should see our new toolbar with our button to the left. Since the toolbars both have the same background, they are a bit difficult to differentiate. So, we are going to change the appearance of the bottom bar using the ui configuration option: { docked: 'top', xtype: 'toolbar', ui: 'light', items: [ {text: 'My Button'} ] } The ui configuration is the shorthand for a particular set of styles in Sencha Touch. There are several ui styles included with Sencha Touch, and later on, we will show you how to make your own. Styling buttons Buttons can also use the ui configuration setting, for which they offer several different options: normal: This is the default button back: This is a button with the left side narrowed to a point round: This is a more drastically rounded button small: This is a smaller button action: This is a brighter version of the default button (the color varies according to the active color of the theme, which we will see later) forward: This is a button with the right side narrowed to a point Buttons also have some color options built into the ui option. These color options are confirm and decline. These options are combined with the previous shape options using a hyphen; for example, confirm-small or decline-round. Let's add some new buttons and see how this looks on our screen. Locate the items list with our button in the second toolbar: items: [ {text: 'My Button'} ] Replace that old items list with the following new items list: items: [ { text: 'Back', ui: 'back' }, { text: 'Round', ui: 'round' }, { text: 'Small', ui: 'small' }, { text: 'Normal', ui: 'normal' }, { text: 'Action', ui: 'action' }, { text: 'Forward', ui: 'forward' } ] This will produce a series of buttons across the top of our toolbar. As you may notice, all of our buttons are aligned to the left. You can move buttons to the right by adding a spacer xtype in front of the buttons you want pushed to the right. Try this by adding the following between our Forward and Action buttons: { xtype: 'spacer'}, This will make the Forward button move over to the right-hand side of the toolbar: Since buttons can actually be used anywhere, we can add some to our title bar and use the align property to control where they appear. Modify the titlebar for our first panel and add an items section, as shown in the following code: { xtype: 'titlebar', docked: 'top', title: 'About TouchStart', items: [ { xtype: 'button', text: 'Left', align: 'left' }, { xtype: 'button', text: 'Right', align: 'right' } ] } Now we should have two buttons in our title bar, one on either side of the title: Let's also add some buttons to the panel container so we can see what the ui options confirm and decline look like. Locate the end of the items section of our HelloPanel container and add the following after the second toolbar: { xtype: 'button', text: 'Confirm', ui: 'confirm', width: 100 }, { xtype: 'button', text: 'Decline', ui: 'decline', width: 100 } There are two things you may notice that differentiate our panel buttons from our toolbar buttons. The first is that we declare xtype:'button' in our panel but we don't in our toolbar. This is because the toolbar assumes it will contain buttons and xtype only has to be declared if you use something other than a button. The panel does not set a default xtype attribute, so every item in the panel must declare one. The second difference is that we declare width for the buttons. If we don't declare width when we use a button in a panel, it will expand to the full width of the panel. On the toolbar, the button auto-sizes itself to fit the text. You will also see that our two buttons in the panel are mashed together. You can separate them out by adding margin: 5 to each of the button configuration sections. These simple styling options can help make your application easier to navigate and provide the user with visual clues for important or potentially destructive actions. The tab bar The tab bar at the bottom also understands the ui configuration option. In this case, the available options are light and dark. The tab bar also changes the icon appearance based on the ui option; a light toolbar will have dark icons and a dark toolbar will have light icons. These icons are actually part of a special font called Pictos. Sencha Touch started using the Pictos font in Version 2.2 instead of images icons because of compatibility issues on some mobile devices. The icon mask from previous versions of Sencha Touch is available but has been discontinued as of Version 2.2. You can see some of the icons available in the documentation for the Ext.Button component: http://docs.sencha.com/touch/2.2.0/#!/api/Ext.Button If you're curious about the Pictos font, you can learn more about it at http://pictos.cc/
Read more
  • 0
  • 0
  • 4404

article-image-using-location-data-phonegap
Packt
30 Oct 2013
11 min read
Save for later

Using Location Data with PhoneGap

Packt
30 Oct 2013
11 min read
(For more resources related to this topic, see here.) An introduction to Geolocation The term geolocation is used in order to refer to the identification process of the real-world geographic location of an object. Devices that are able to detect the user's position are becoming more common each day and we are now used to getting content based on our location ( geo targeting ). Using the Global Positioning System (GPS )—a space-based satellite navigation system that provides location and time information consistently across the globe—you can now get the accurate location of a device. During the early 1970s, the US military created Navstar, a defense navigation satellite system. Navstar was the system that created the basis for the GPS infrastructure used today by billions of devices. Since 1978 more than 60 GPS satellites have been successfully placed in the orbit around the Earth (refer to http://en.wikipedia.org/wiki/List_of_GPS_satellite_launches for a detailed report about the past and planned launches). The location of a device is represented through a point. This point is comprised of two components: latitude and longitude. There are many methods for modern devices to determine the location information, these include: Global Positioning System (GPS) IP address GSM/CDMA cell IDs Wi-Fi and Bluetooth MAC address Each approach delivers the same information; what changes is the accuracy of the device's position. The GPS satellites continuously transmit information that can parse, for example, the general health of the GPS array, roughly, where all of the satellites are in orbit, information on the precise orbit or path of the transmitting satellite, and the time of the transmission. The receiver calculates its own position by timing the signals sent by any of the satellites in the array that are visible. The process of measuring the distance from a point to a group of satellites to locate a position is known as trilateration . The distance is determined using the speed of light as a constant along with the time that the signal left the satellites. The emerging trend in mobile development is GPS-based "people discovery" apps such as Highlight, Sonar, Banjo, and Foursquare. Each app has different features and has been built for different purposes, but all of them share the same killer feature: using location as a piece of metadata in order to filter information according to the user's needs. The PhoneGap Geolocation API The Geolocation API is not a part of the HTML5 specification but it is tightly integrated with mobile development. The PhoneGap Geolocation API and the W3C Geolocation API mirror each other; both define the same methods and relative arguments. There are several devices that already implement the W3C Geolocation API; for those devices you can use native support instead of the PhoneGap API. As per the HTML specification, the user has to explicitly allow the website or the app to use the device's current position. The Geolocation API is exposed through the geolocation object child of the navigator object and consists of the following three methods: getCurrentPosition() returns the device position. watchPosition() watches for changes in the device position. clearWatch() stops the watcher for the device's position changes. The watchPosition() and clearWatch() methods work in the same way that the setInterval() and clearInterval() methods work; in fact the first one returns an identifier that is passed in to the second one. The getCurrentPosition() and watchPosition() methods mirror each other and take the same arguments: a success and a failure callback function and an optional configuration object. The configuration object is used in order to specify the maximum age of a cached value of the device's position, to set a timeout after which the method will fail and to specify whether the application requires only accurate results. var options = {maximumAge: 3000, timeout: 5000, enableHighAccuracy: true }; navigator.geolocation.watchPosition(onSuccess, onFailure, options); Only the first argument is mandatory; but it's recommended to handle always the failure use case. The success handler function receives as argument, a Position object. Accessing its properties you can read the device's coordinates and the creation timestamp of the object that stores the coordinates. function onSuccess(position) { console.log('Coordinates: ' + position.coords); console.log('Timestamp: ' + position.timestamp); } The coords property of the Position object contains a Coordinates object; so far the most important properties of this object are longitude and latitude. Using those properties it's possible to start to integrate positioning information as relevant metadata in your app. The failure handler receives as argument, a PositionError object. Using the code and the message property of this object you can gracefully handle every possible error. function onError(error) { console.log('message: ' + error.message); console.log ('code: ' + error.code); } The message property returns a detailed description of the error, the code property returns an integer; the possible values are represented through the following pseudo constants: PositionError.PERMISSION_DENIED, the user denies the app to use the device's current position PositionError.POSITION_UNAVAILABLE, the position of the device cannot be determined If you want to recover the last available position when the POSITION_UNAVAILABLE error is returned, you have to write a custom plugin that uses the platform-specific API. Android and iOS have this feature. You can find a detailed example at http://stackoverflow.com/questions/10897081/retrieving-last-known-geolocation-phonegap. PositionError.TIMEOUT, the specified timeout has elapsed before the implementation could successfully acquire a new Position object JavaScript doesn't support constants such as Java and other object-oriented programming languages. With the term "pseudo constants", I refer to those values that should never change in a JavaScript app. One of the most common tasks to perform with the device position information is to show the device location on a map. You can quickly perform this task by integrating Google Maps in your app; the only requirement is a valid API key. To get the key, use the following steps: Visit the APIs console at https://code.google.com/apis/console and log in with your Google account. Click the Services link on the left-hand menu. Activate the Google Maps API v3 service. Time for action – showing device position with Google Maps Get ready to add a map renderer to the PhoneGap default app template. Refer to the following steps: Open the command-line tool and create a new PhoneGap project named MapSample. $ cordova create ~/the/path/to/your/source/ mapmample com.gnstudio.pg.MapSample MapSample Add the Geolocation API plugin using the command line. $ cordova plugins add https: //git-wip-us.apache.org /repos/asf/cordova-plugin-geolocation.git Go to the www folder, open the index.html file, and add a div element with the id value #map inside the main div of the app below the #deviceready one. <div id='map'></div> Add a new script tag to include the Google Maps JavaScript library. <script type="text/javascript" src ="https: //maps.googleapis.com/maps/api/js?key= YOUR_API_KEY &sensor=true"> </script> Go to the css folder and define a new rule inside the index.css file to give to the div element and its content an appropriate size. #map{ width: 280px; height: 230px; display: block; margin: 5px auto; position: relative; } Go to the js folder, open the index.js file, and define a new function named initMap. initMap: function(lat, long){ // The code needed to show the map and the // device position will be added here } In the body of the function, define an options object in order to specify how the map has to be rendered. var options = { zoom: 8, center: new google.maps.LatLng(lat, long), mapTypeId: google.maps.MapTypeId.ROADMAP }; Add to the body of the initMap function the code to initialize the rendering of the map, and to show a marker representing the current device's position over it. var map = new google.maps.Map(document.getElementById('map'), options); var markerPoint = new google.maps.LatLng(lat, long); var marker = new google.maps.Marker({ position: markerPoint, map: map, title: 'Device's Location' }); Define a function to use as the success handler and call from its body the initMap function previously defined. onSuccess: function(position){ var coords = position.coords; app.initMap(coords.latitude, coords.longitude); } Define another function in order to have a failure handler able to notify the user that something went wrong. onFailure: function(error){ navigator.notification.alert(error.message, null); } Go into the deviceready function and add as the last statement the call to the Geolocation API needed to recover the device's position. navigator.geolocation.getCurrentPosition(app.onSuccess, app.onError, {timeout: 5000, enableAccuracy: false}); Open the command-line tool, build the app, and then run it on your testing devices. $ cordova build $ cordova run android What just happened? You integrated Google Maps inside an app. The map is an interactive map most users are familiar with—the most common gestures are already working and the Google Street View controls are already enabled. To successfully load the Google Maps API on iOS, it's mandatory to whitelist the googleapis.com and gstatic.com domains. Open the .plist file of the project as source code (right-click on the file and then Open As | Source Code ) and add the following array of domains: <key>ExternalHosts</key> <array> <string>*.googleapis.com</string> <string>*.gstatic.com</string> </array> Other Geolocation data In the previous example, you only used the latitude and longitude properties of the position object that you received. There are other attributes that can be accessed as properties of the Coordinates object: altitude, the height of the device, in meters, above the sea level. accuracy, the accuracy level of the latitude and longitude, in meters; it can be used to show a radius of accuracy when mapping the device's position. altitudeAccuracy, the accuracy of the altitude in meters. heading, the direction of the device in degrees clockwise from true north. speed, the current ground speed of the device in meters per second. Latitude and longitude are the best supported of these properties, and the ones that will be most useful when communicating with remote APIs. The other properties are mainly useful if you're developing an application for which Geolocation is a core component of its standard functionality, such as apps that make use of this data to create a flow of information contextualized to the geolocation data. The accuracy property is the most important of these additional features, because as an application developer, you typically won't know which particular sensor is giving you the location and you can use the accuracy property as a range in your queries to external services. There are several APIs that allow you to discover interesting data related to a place; among these the most interesting are the Google Places API and the Foursquare API. The Google Places and Foursquare online documentation is very well organized and it's the right place to start if you want to dig deeper into these topics. You can access the Google Places docs at https://developers.google.com/maps/documentation/javascript/places and Foursquare at https://developer.foursquare.com/. The itinero reference app for this article implements both the APIs. In the next example, you will look at how to integrate Google Places inside the RequireJS app. In order to include the Google Places API inside an app, all you have to do is add the libraries parameter to the Google Maps API call. The resulting URL should look similar to http://maps.google.com/maps/api/js?key=SECRET_KEY&sensor=true&libraries=places. The itinero app lets users create and plan a trip with friends. Once the user provides the name of the trip, the name of the country to be visited, and the trip mates and dates, it's time to start selecting the travel, eat, and sleep options. When the user selects the Eat option, the Google Places data provider will return bakeries, take-out places, groceries, and so on, close to the trip's destination. The app will show on the screen a list of possible places the user can select to plan the trip. For a complete list of the types of place searches supported by the Google API, refer to the online documentation at https://developers.google.com/places/documentation/supported_types.
Read more
  • 0
  • 0
  • 6679

article-image-social-networks
Packt
29 Oct 2013
15 min read
Save for later

Social Networks

Packt
29 Oct 2013
15 min read
(For more resources related to this topic, see here.) One window to rule them all Since we want to give our users the ability to post their messages on multiple social networks at once, it makes perfect sense to keep our whole application in a single window. It will be comprised of the following sections: The top section of the window will contain labels and a text area for message input. The text area will be limited to 140 characters in order to comply with Twitter's message limitation. As the user types his or her message, a label showing the number of characters will be updated. The bottom section of the window will use an encapsulating view that will contain multiple image views. Each image view will represent a social network to which the application will post the messages (in our case, Twitter and Facebook). But we can easily add more networks that will have their representation in this section. Each image view acts as a toggle button in order to select if the message will be sent to a particular social network or not. Finally, in the middle of those two sections, we will add a single button that will be used to publish the message from the text area. Code while it is hot! With our design in hand, we can now move on to create our user interface. Our entire application will be contained in a single window, so this is the first thing we will create. We will give it a title as well as a linear background gradient that changes from purple at the top to black at the bottom of the screen. Since we will add other components to it, we will keep its reference in the win variable: var win = Ti.UI.createWindow({ title: 'Unified Status', backgroundGradient: { type: 'linear', startPoint: { x: '0%', y: '0%' }, endPoint: { x: '0%', y: '100%' }, colors: [ { color: '#813eba'}, { color: '#000' } ] } }); The top section We will then add a new white label at the very top of the window. It will span 90% of the window's width, have a bigger font than other labels, and will have its text aligned to the left. Since this label will never be accessed later on, we will invoke our createLabel function right into the add function of the window object: win.add(Ti.UI.createLabel({ text: 'Post a message', color: '#fff', top: 4, width: '90%', textAlign: Ti.UI.TEXT_ALIGNMENT_LEFT, font: { fontSize: '22sp' } })); We will now move on to create our text area where our users will enter their messages. It will be placed right under the label previously created, occupy 90% of the screen's width, have a slightly bigger font, and have a thick, rounded, dark border. It will also be limited to 140 characters. It is also important that we don't forget to add this newly created object to our main window: var txtStatus = Ti.UI.createTextArea({ top: 37, width: '90%', height: 100, color: '#000', maxLength: 140, borderWidth: 3, borderRadius: 4, borderColor: '#401b60', font: { fontSize: '16sp' } }); win.add(txtStatus); The second label that will complement our text area will be used to indicate how many characters are currently present in the user's message. So, we will now create a label just underneath the text area and assign it a default text value. It will span 90% of the screen's width and have its text aligned to the right. Since this label will be updated dynamically when the text area's value changes, we will keep its reference in a variable named lblCount. As we did with our previous UI components, we will add our label to our main window using the following code: var lblCount = Ti.UI.createLabel({ text: '0/140', top: 134, width: '90%', color: '#fff', textAlign: Ti.UI.TEXT_ALIGNMENT_RIGHT }); win.add(lblCount); The last control from the top section will be our Post button. It will be placed right under the text area and centered horizontally using the following code: var btnPost = Ti.UI.createButton({ title: 'Post', top: 140, width: 150 }); win.add(btnPost); By not specifying any left or right property, the component is automatically centered. This is pretty useful to keep in mind while designing our user interfaces, as it frees us from having to do calculations in order to center something on the screen. Staying within the limits Even though the text area's maxLength property will ensure that the message length will not exceed the limitation we have set, we need to give our users feedback as they are typing their message. To achieve this, we will add an event listener on the change event of our text area. Every time; the text area's content changes, we will update the lblCount label with the number of characters our message contains: txtStatus.addEventListener('change', function(e) { lblCount.text = e.value.length + '/140'; We will also add a condition to check if our user's message is close to reaching its limit. If that is the case, we will change the label's color to red, if not, it will return to its original color: if (e.value.length > 120) { lblCount.color = 'red'; } else { lblCount.color = 'white' } Our last conditional check will be enabling the Post button only if there is actually a message to be posted. This will prevent our users from posting empty messages: btnPost.enabled = !(e.value.length === 0); }); Setting up our Post button Probably the most essential component in our application would be the Post button. We won't be able to post anything online (yet) by clicking on it, as there are things we will still need to add. We will add an event listener for the click event on the Post button. If the on-screen keyboard is displayed, we will call the blur function of the text area in order to hide it: btnPost.addEventListener('click', function() { txtStatus.blur(); Also, we will reset the value to the text area and the character count on the label, so that the interface is ready to enter a new message: txtStatus.value = ''; lblCount.text = '0/140'; }); The bottom section With all our message input mechanisms in place, we will now move on to our bottom section. All components from this section will be contained in a view that will be placed at the bottom of the screen. It will span 90% of the screen's width, and its height will adapt to its content. We will store its reference in a variable named bottomView for later use: var bottomView = Ti.UI.createView({ bottom: 4, width: '90%', height: Ti.UI.SIZE }); We will then create our toggle switches for each social network that our application interacts with. Since we want something sexier than regular switch components, we will create our own switch using a regular image view. Our first image view will be used to toggle the use of Facebook. It will have a dark blue background (similar to Facebook's logo) and will have a background image representing Facebook's logo with a gray background, so that it appears disabled. It will be positioned to the left of its parent view, and will have a borderRadius value of 4 in order to give it a rounded aspect. We will keep its reference in the fbView variable and then add this same image view to our bottom view using the following code: var fbView = Ti.UI.createImageView({ backgroundColor: '#3B5998', image: 'images/fb-logo-disabled.png', borderRadius: 4, width: 100, left: 10, height: 100 }); bottomView.add(fbView); We will create a similar image view (in almost every way), but this time for Twitter. So the background color and the image will be different. Also, it will be positioned to the right of our container view. We will store its reference in the twitView variable and then add it to our bottom view using the following code: var twitView = Ti.UI.createImageView({ backgroundColor: '#9AE4E8', image: 'images/twitter-logo-disabled.png', borderRadius: 4, width: 100, right: 10, height: 100 }); bottomView.add(twitView); Last but not the least, it is imperative that we do not forget to add our bottomView container object into our window. Also, we will open the window so that our users can interact with it using the following code: win.add(bottomView); win.open(); What if the user rotates the device? At this stage, if our user were to rotate the device (to landscape), nothing would happen on the screen. The reason behind this is because we have not taken any action to make our application compatible with the landscape mode. In many cases, this would require some changes to how the user interface is created depending on the orientation. But since our application is fairly simple, and most of our layout relies on percentages, we can activate the landscape mode without any modification to our code. To activate the landscape mode, we will update the orientations section from our tiapp.xml configuration file. It is mandatory to have at least one orientation present in this section (it doesn't matter which one it is). We want our users to be able to use the application, no matter how they hold their device: <iphone> <orientations device="iphone"> <orientation>Ti.UI.PORTRAIT</orientation> <orientation>Ti.UI.UPSIDE_PORTRAIT</orientation> <orientation>Ti.UI.LANDSCAPE_LEFT</orientation> <orientation>Ti.UI.LANDSCAPE_RIGHT</orientation> </orientations> </iphone> By default, no changes are required for Android applications since the default behavior supports orientation changes. There are, of course, ways to limit orientation in the manifest section, but this subject falls out of this article's scope. See it in action We have now implemented all the basic user interface. We can now test it and see if it behaves as we anticipated. We will click on the Run button from the App Explorer tab, as we did many times before. We now have our text area at the top with our two big images views at the bottom, each with the social network's logo. We can already test the message entry (with the character counter incrementing) by clicking on the Post button. Now if we rotate the iOS simulator (or the Android emulator), we can see that our layout adapts well to the landscape mode. To rotate the iOS simulator, you need to use the Hardware menu or you can use Cmd-Left and Cmd-Right on the keyboard. If you are using the Android emulator, there is no menu, but you can change the orientation using Ctrl + F12. The reason this all fits so well is because most of our dimensions are done using percentages. That means that our components will adapt and use the available space on the screen. Also, we positioned the bottom view using the bottom property; which meant that it will stick to the bottom of the screen, no matter how tall it is. There is a module for that Since we don't want to interact with the social network through manual asynchronous HTTP requests, we will leverage the Facebook native module provided with Titanium. Since it comes with Titanium SDK, there is no need to download or copy any file. All we need to do is add a reference (one for each target platform), in the modules section of our tiapp.xml file as follows: <modules> <module platform="android">facebook</module> <module platform="iphone">facebook</module> </modules> Also, we need to add the following property at the end of our configuration file, and replace the FACEBOOK_APPID parameter with the application ID that was provided when we created our app online. <property name="ti.facebook.appid">[FACEBOOK_APPID]</property> Why do we have to reference a module even though it comes bundled with the Titanium framework? Mostly, it is to avoid framework bloat; it is safe to assume that most applications developed using Titanium won't require interaction with Facebook. This is the reason for having it in a separate module that can be loaded on demand. Linking our mobile app to our Facebook app With our Facebook module loaded, we will now populate the necessary properties before making any call to the network. We will need to set the appid property in our code; since we have already defined it as a property in our tiapp.xml file, we can access it through the Properties API. This is a neat way to externalize application parameters, thus preventing us to hardcode them in our JavaScript code: fb.appid = Ti.App.Properties.getString('ti.facebook.appid'); We will also set the proper permissions that we will need while interacting with the server. (In this case, we only want to publish messages on the user's wall): fb.permissions = ['publish_actions']; It is important to set the appid and permissions properties before calling the authorize function. This makes sense since we want Facebook to authorize our application with a defined set of permissions from the get-go. Allowing our user to log in and log out at the click of a button We want our users to be able to connect (and disconnect) at their will from one social network, just by pressing the same view on the screen. To achieve this, we will create a function called toggleFacebook that will have a single parameter: function toggleFacebook(isActive) { If we want the function to make the service active, then we will verify if the user is already logged in to Facebook. If not, we will ask Facebook to authorize the application using the function with the same name. If the parameter indicates that we want to make the service inactive, we will log out from Facebook altogether: if (isActive) { if (!fb.loggedin) { fb.authorize(); } } else { fb.logout(); } } Now, all that we need to do is create an event listener on the click event for our Facebook image view and simply toggle between the two states depending whether the user is logged in or not: fbView.addEventListener('click', function() { toggleFacebook(!fb.loggedIn); }); The authorize function prompts the user to log in (if he or she is not already logged in), and authorize his or her application. It kind of makes sense that Facebook requires user validation before delegating the right to post something on his or her behalf. Handling responses from Facebook We have now completely implemented the Facebook login/logout mechanism into our application, but we still need to provide some feedback to our users. The Facebook module provides two event listeners that allow us to track when our user will have logged in or out. In the login event listener, we will check if the user is logged in successfully. If he or she did, we will update the image view's image property with the colored logo. If there was any error during authentication, or if the operation was simply cancelled, we will show an alert, as given in the following code: fb.addEventListener('login', function(e) { if (e.success) { fbView.image = 'images/fb-logo.png'; } else if (e.error) { alert(e.error); } else if (e.cancelled) { alert("Canceled"); } }); In the logout event listener, we will update the image view's image property with the grayed out Facebook logo using the following code: fb.addEventListener('logout', function(e) { fbView.image = 'images/fb-logo-disabled.png'; }); Posting our message on Facebook Since we are now connected to Facebook, and our application is authorized to post, we can now post our messages on this particular social network. To do this, we will create a new function named postFacebookMessage, with a single parameter, and that will be the message string to be posted: function postFacebookMessage(msg) { Inside this function, we will call the requestWithGraphPath function from the Facebook native module. This function can look fairly complex at first glance, but we will go over each parameter in detail. The parameters are as follows: The Graph API path requested (My feed). A dictionary object containing all of the properties required by the call (just the message). The HTTP method used for this call (POST). The callback function invoked when the request completes (this function simply checks the result from the call. In case of error, an alert is displayed). fb.requestWithGraphPath('me/feed', { message: msg }, "POST", function(e) { if (e.success) { Ti.API.info("Success! " + e.result); } else { if (e.error) { alert(e.error); } else { alert("Unknown result"); } } } ); } We will then update the click event handler for the Post button and call the postFacebookMessage function if the user is logged in to Facebook: btnPost.addEventListener('click', function() { if (fb.loggedIn) { postFacebookMessage(txtStatus.value); } ... }); With this, our application can post messages on our user's Facebook wall. Summary In this article, we learned how to create server-side applications on two popular social networking websites. We learned how to interact with those networks in terms of API and authentication. We also learned how to handle device rotation as well as use the native platform setting Windows. Finally, we covered Titanium menus and activities. Resources for Article: Further resources on this subject: Appcelerator Titanium: Creating Animations, Transformations, and Understanding Drag-and-drop [Article] augmentedTi: The application architecture [Article] Basic Security Approaches [Article]
Read more
  • 0
  • 0
  • 4718

article-image-building-hello-world-application
Packt
29 Oct 2013
6 min read
Save for later

Building a Hello World application

Packt
29 Oct 2013
6 min read
(For more resources related to this topic, see here.) The Hello World application In the previous sections, we saw how to set up environments for development of Sencha Touch. Now let's start with the Hello World application. First of all, create a new folder in your web server and name it sencha-touch-start. Create a subfolder lib inside this folder. In this folder, we will store our Sencha Touch resources. Create two more subfolders inside the lib folder and name them js and css respectively. Copy the sencha-touch-all.js file from the SDK, which we had downloaded, to the lib/js folder. Copy the sencha-touch.css file from SDK to the lib/css folder. Now, create a new file in the sencha-touch-start folder, name it index.html, and add the following code snippet to it: <!DOCTYPE html><html><head><meta charset="utf-8"><title>Hello World</title><script src = "lib/js/sencha-touch-all.js" type="text/javascript"></script><link href="lib/css/sencha-touch.css" rel="stylesheet"type="text/css" /></head><body></body></html> Now create a new file in the sencha-touch-start folder, name it app.js, and add the following code snippet to it: Ext.application({name: 'Hello World',launch: function () {var panel = Ext.create('Ext.Panel', {fullscreen: true,html: 'Welcome to Sencha Touch'});Ext.Viewport.add(panel);}}); Add a link to the app.js file in the index.html page; we created the following link to sencha-touch-all.js and sencha-touch.css: <script src = "app.js" type="text/javascript"></script> Here in the code, Ext.application({..}) creates an instance of the Ext.Application class and initializes our application. The name property defines the name of our application. The launch property defines what an application should do when it starts. This property should always be set to a function inside which we will add our code to initialize the application. Here in this function, we are creating a panel with Ext.create and adding it to Ext.Viewport. Ext. Viewport is automatically created and initialized by the Sencha Touch framework. This is like a base container that holds other components of the application. At this point, your application folder structure should look like this: Now run the application in the browser and you should see the following screen: If your application does not work, please check your web server. It should be turned on, and the steps mentioned earlier should be repeated. Now we will go through some of the most important features and configurations of Sencha Touch. These are required to build real-time Sencha Touch applications. Introduction to layouts Layouts give a developer a number of options to arrange components inside the application. Sencha Touch offers the following four basic layouts: fit hbox vbox card hbox and vbox layouts arrange items horizontally and vertically, respectively. Let's modify our previous example by adding hbox and vbox layouts to it. Modify the code in the launch function of app.js as follows: var panel = Ext.create('Ext.Panel', {fullscreen: true,layout: 'hbox',items: [{xtype: 'panel',html: 'BOX1',flex: 1,style: {'background-color': 'blue'}},{xtype: 'panel',html: 'BOX2',flex: 1,style: {'background-color': 'red'}},{xtype: 'panel',html: 'BOX3',flex: 1,style: {'background-color': 'green'}}]});Ext.Viewport.add(panel); In the preceding code snippet, we specified the layout for a panel by setting the layout: 'hbox' property, and added three items to the panel. Another important configuration to note here is flex. The flex configuration is unique to the hbox and vbox layouts. It controls how much space the component will take up, proportionally, in the overall layout. Here, we have specified flex : 1 to all the child containers; that means the height of the main container will be divided equally in a 1:1:1 ratio among all the three containers. For example, if the height of the main container is 150 px, the height of each child container would be 50 px. Here, the height of the main container would be dependent on the browser width. So, it will automatically adjust itself. This is how Sencha Touch adaptive layout works; we will see this in detail in later sections. If you run the preceding code example in your browser, you should see the following screen: Also, we can change the layout to vbox by setting layout: 'vbox', and you should see the following screen: When we specify a fit layout, a single item will automatically expand to cover the whole space of the container. If we add more than one item and specify only the fit layout, only the first item would be visible at a time. The card layout arranges items in a stack of cards and only one item will be visible at a time, but we can switch between items using the setActiveItem function. We will see this in detail in a later section. Panel – a basic container We have already mentioned the word "panel" in previous examples. It's a basic container component of the Sencha Touch framework. It's basically used to hold items and arrange them in a proper layout by adding the layout configuration. Besides this, it is also used as overlays. Overlays are containers that float over your application. Overlay containers can be positioned relative to some other components. Create another folder in your web server, name it panel- demo, and copy all the files and folders from the sencha-touch-start folder of the previous example. Modify the title in the index.html file. <title>Panel Demo</title> Modify app.js as follows: Ext.application({name: 'PanelDemo',launch: function () {var panel = Ext.create('Ext.Panel', {fullscreen: true,items: [{xtype: 'button',text: 'Show Overlay',listeners: {tap: function(button){var overlay = Ext.create('Ext.Panel', {height: 100,width: 300,html: 'Panel asOverlay'});overlay.showBy(button);}}}]});Ext.Viewport.add(panel);}}); In the preceding code snippet, we have added button as the item in the panel and added listeners for the button. We are binding a tap event to a function for the button. On the tap of the button, we are creating another panel as an overlay and showing it using overlay. showBy(button). Summary This article thus provided us with details on building a Hello World application, which gave you further introduction to the most used components and features of Sencha Touch in real-time applications. Resources for Article : Further resources on this subject: Creating a Simple Application in Sencha Touch [Article] Sencha Touch: Layouts Revisited [Article] Sencha Touch: Catering Form Related Needs [Article]
Read more
  • 0
  • 0
  • 3256

article-image-gesture
Packt
25 Oct 2013
5 min read
Save for later

Gesture

Packt
25 Oct 2013
5 min read
(For more resources related to this topic, see here.) Gestures While there are ongoing arguments in the courts of America at the time of writing over who invented the likes of dragging images, it is without a doubt that a key feature of iOS is the ability to use gestures. To put it simply, when you tap the screen to start an app or select a part of an image to enlarge it or anything like that, you are using gestures. A gesture (in terms of iOS) is any touch interaction between the UI and the device. With iOS 6, there are six gestures the user has the ability to use. These gestures, along with brief explanations, have been listed in the following table: Class Name and type Gesture UIPanGesture Recognizer PanGesture; Continuous type Pan images or over-sized views by dragging across the screen UISwipeGesture Recognizer SwipeGesture; Continuous type Similar to panning, except it is a swipe UITapGesture Recognizer TapGesture; Discrete type Tap the screen a number of times (configurable) UILongPressGesture Recognizer LongPressGesture; Discrete type Hold the finger down on the screen UIPinchGesture Recognizer PinchGesture; Continuous type Zoom by pinching an area and moving your fingers in or out UIRotationGesture Recognizer RotationGesture; Continuous type Rotate by moving your fingers in opposite directions Gestures can be added by programming or via Xcode. The available gestures are listed in the following screenshot with the rest of the widgets on the right-hand side of the designer: To add a gesture, drag the gesture you want to use under the view on the View bar (shown in the following screenshot): Design the UI as you want and while pressing the Ctrl key, drag the gesture to what you want to recognize using the gesture. In my example, the object you want to recognize is anywhere on the screen. Once you have connected the gesture to what you want to recognize, you will see the configurable options of the gesture. The Taps field is the number of taps required before the Recognizer is triggered, and the Touches field is the number of points onscreen required to be touched for the Recognizer to be triggered. When you come to connect up the UI, the gesture must also be added. Gesture code When using Xcode, it is simple to code gestures. The class defined in the Xcode design for the tapping gesture is called tapGesture and is used in the following code: private int tapped = 0; public override void ViewDidLoad() { base.ViewDidLoad(); tapGesture.AddTarget(this, new Selector("screenTapped")); View.AddGestureRecognizer(tapGesture); } [Export("screenTapped")]public void SingleTap(UIGestureRecognizer s) { tapped++; lblCounter.Text = tapped.ToString(); } There is nothing really amazing to the code; it just displays how many times the screen has been tapped. The Selector method is called by the code when the tap has been seen. The method name doesn't make any difference as long as the Selector and Export names are the same. Types When the gesture types were originally described, they were given a type. The type reflects the number of messages sent to the Selector method. A discrete one generates a single message. A continuous one generates multiple messages, which requires the Selector method to be more complex. The complexity is added by the Selector method having to check the State of the gesture to decide on what to do with what message and whether it has been completed. Adding a gesture in code It is not a requirement that Xcode be used to add a gesture. To perform the same task in the following code as my preceding code did in Xcode is easy. The code will be as follows: UITapGestureRecognizer t'pGesture = new UITapGestureRecognizer() { NumberOfTapsRequired = 1 }; The rest of the code from AddTarget can then be used. Continuous types The following code, a Pinch Recognizer, shows a simple rescaling. There are a couple of other states that I'll explain after the code. The only difference in the designer code is that I have UIImageView instead of a label and a UIPinchGestureRecognizer class instead of a UITapGestureRecognizer class. public override void ViewDidLoad() { base.ViewDidLoad(); uiImageView.Image =UIImage.FromFile("graphics/image.jpg") Scale(new SizeF(160f, 160f); pinchGesture.AddTarget(this, new Selector("screenTapped")); uiImageView.AddGestureRecognizer(pinchGesture); } [Export("screenTapped")]public void SingleTap(UIGestureRecognizer s) { UIPinchGestureRecognizer pinch = (UIPinchGestureRecognizer)s; float scale = 0f; PointF location; switch(s.State) { case UIGestureRecognizerState.Began: Console.WriteLine("Pinch begun"); location = s.LocationInView(s.View); break; case UIGestureRecognizerState.Changed: Console.WriteLine("Pinch value changed"); scale = pinch.Scale; uiImageView.Image = UIImage FromFile("graphics/image.jpg") Scale(new SizeF(160f, 160f), scale); break; case UIGestureRecognizerState.Cancelled: Console.WriteLine("Pinch cancelled"); uiImageView.Image = UIImage FromFile("graphics/image.jpg") Scale(new SizeF(160f, 160f)); scale = 0f; break; case UIGestureRecognizerState.Recognized: Console.WriteLine("Pinch recognized"); break; } } Other UIGestureRecognizerState values The following table gives a list of other Recognizer states: State Description Notes Possible Default state; gesture hasn't been recognized Used by all gestures Failed Gesture failed No messages sent for this state Translation Direction of pan Used in the pan gesture Velocity Speed of pan Used in the pan gesture In addition to these, it should be noted that discrete types only use Possible and Recognized states. Summary Gestures certainly can add a lot to your apps. They can enable the user to speed around an image, move about a map, enlarge and reduce, as well as select areas of anything on a view. Their flexibility underpins why iOS is recognized as being an extremely versatile device for users to manipulate images, video, and anything else on-screen. Resources for Article: Further resources on this subject: Creating and configuring a basic mobile application [Article] So, what is XenMobile? [Article] Building HTML5 Pages from Scratch [Article]
Read more
  • 0
  • 0
  • 5908

article-image-creating-quizzes
Packt
24 Oct 2013
9 min read
Save for later

Creating Quizzes

Packt
24 Oct 2013
9 min read
(For more resources related to this topic, see here.) Creating a short-answer question For this task, we will create a card to host an interface for a short-answer question. This type of question allows the user to input their answers via the keyboard. Evaluating this type of answer can be especially challenging, since there could be several correct answers and users are prone to make spelling mistakes. Engage Thrusters Create a new card and name it SA. Copy the Title label from the Main card and paste it onto the new SA card. This will ensure the title label field has a consistent format and location. Copy the Question label from the TF card and paste it onto the new SA card. Copy the Progress label from the TF card and paste it onto the new SA card. Copy the Submit button from the Sequencing card and paste it onto the new SA card. Drag a text entry field onto the card and make the following modifications: Change the name to answer. Set the size to 362 by 46. Set the location to 237, 185. Change the text size to 14. We are now ready to program our interface. Enter the following code at the card level: on preOpenCard global qNbr, qArray # Section 1 put 1 into qNbr # Section 2 put "" into fld "question" put "" into fld "answer" put "" into fld "progress" # Section 3 put "What farm animal eats shrubs, can be eaten, and are smaller than cows?" into qArray["1"]["question"] put "goat" into qArray["1"]["answer"] -- put "What is used in pencils for writing?" into qArray["2"]["question"] put "lead" into qArray["2"]["answer"] -- put "What programming language are you learning" into qArray["3"] ["question"] put "livecode" into qArray["3"]["answer"] end preOpenCard In section 1 of this code, we reset the question counter (qNbr) variable to 1. Section 2 contains the code to clear the question, answer, and progress fields. Section 3 populates the question/answer array (qArray). As you can see, this is the simplest array we have used. It only contains a question and answer pairing for each row. Our last step for the short answer question interface is to program the Submit button. Here is the code for that button: on mouseUp global qNbr, qArray local tResult # Section 1 if the text of fld "answer" contains qArray[qNbr]["answer"] then put "correct" into tResult else put "incorrect" into tResult end if #Section 2 switch tResult case "correct" if qNbr < 3 then answer "Very Good." with "Next" titled "Correct" else answer "Very Good." with "Okay" titled "Correct" end if break case "incorrect" if qNbr < 3 then answer "The correct answer is: " & qArray[qNbr]["answer"] & "." with "Next" titled "Wrong Answer" else answer "The correct answer is: " & qArray[qNbr]["answer"] & "." with "Okay" titled "Wrong Answer" end if break end switch # Section 3 if qNbr < 3 then add 1 to qNbr nextQuestion else go to card "Main" end if end mouseUp Our Submit button script is divided into three sections. The first section (section 1) checks to see if the answer contained in the array (qArray) is part of the answer the user entered. This is a simple string comparison and is not case sensitive. Section 2 of this button's code contains a switch statement based on the local variable tResult. Here, we provide the user with the actual answer if they do not get it right on their own. The final section (section 3) navigates to the next question or to the main card, depending upon which question set the user is on. Objective Complete - Mini Debriefing We have successfully coded our short answer quiz card. Our approach was to use a simple question and data input design with a Submit button. Your user interface should resemble the following screenshot: Creating a picture question card Using pictures as part of a quiz, poll, or other interface can be fun for the user. It might also be more appropriate than simply using text. Let's create a card that uses pictures as part of a quiz. Engage Thrusters Create a new card and name it Pictures. Copy the Title label from the Main card and paste it onto the new Pictures card. This will ensure the title label field has a consistent format and location. Copy the Question label from the TF card and paste it onto the new Pictures card. Copy the Progress label from the TF card and paste it onto the new Pictures card. Drag a Rectangle Button onto the card and make the following customizations: Change the name to picture1. Set the size to 120 x 120. Set the location to 128, 196. Drag a second Rectangle Button onto the card and make the following customizations: Change the name to picture2. Set the size to 120 x 120. Set the location to 336, 196. Upload the following listed files into your mobile application's Image Library. This LiveCode function is available by selecting the Development pull-down menu, then selecting Image Library. Near the bottom of the Image Library dialog is an Import File button. Once your files are uploaded, take note of the ID numbers assigned by LiveCode: q1a1.png q1a2.png q2a1.png q2a2.png q3a1.png q3a2.png With our interface fully constructed, we are now ready to add LiveCode script to the card. Here is the code you will enter at the card level: on preOpenCard global qNbr, qArray # Section 1 put 1 into qNbr set the icon of btn "picture1" to empty set the icon of btn "picture2" to empty # Section 2 put "" into fld "question" put "" into fld "progress" # Section 3 put "Which puppy is real?" into qArray["1"]["question"] put "2175" into qArray["1"]["pic1"] put "2176" into qArray["1"]["pic2"] put "q1a1" into qArray["1"]["answer"] -- put "Which puppy looks bigger?" into qArray["2"]["question"] put "2177" into qArray["2"]["pic1"] put "2178" into qArray["2"]["pic2"] put "q2a2" into qArray["2"]["answer"] -- put "Which scene is likely to make her owner more upset?" into qArray["3"]["question"] put "2179" into qArray["3"]["pic1"] put "2180" into qArray["3"]["pic2"] put "q3a1" into qArray["3"]["answer"] end preOpenCard In section 1 of this code, we set the qNbr to 1. This is our question counter. We also ensure that there is no image visible in the two buttons. We do this by setting the icon of the buttons to empty. In section 2, we empty the contents of the two onscreen fields (Question and Progress). In the third section, we populate the question set array (qArray). Each question has an answer that corresponds with the filename of the images you added to your stack in the previous step. The ID numbers of the six images you uploaded are also added to the array, so you will need to refer to your notes from step 7. Our next step is to program the picture1 and picture2 buttons. Here is the code for the picture1 button: on mouseUp global qNbr, qArray # Section 1 if qArray[qNbr]["answer"] contains "a1" then if qNbr < 3 then answer "Very Good." with "Next" titled "Correct" else answer "Very Good." with "Okay" titled "Correct" end if else if qNbr < 3 then answer "That is not correct." with "Next" titled "Wrong Answer" else answer "That is not correct." with "Okay" titled "Wrong Answer" end if end if # Section 2 if qNbr < 3 then add 1 to qNbr nextQuestion else go to card "Main" end if end mouseUp In section 1 of our code, we check to see if the answer from the array contains a1, which indicates that the picture on the left is the correct answer. Based on the answer evaluation, one of two text feedbacks is provided to the user. The name of the button on the feedback dialog is either Next or Okay, depending upon which question set the user is currently on. The second section of this code routes the user to either the main card (if they finished all three questions) or to the next question. Copy the code you entered in the picture1 button and paste it onto the picture2 button. Only one piece of code needs to change. On the first line of the section 1 code, change the string from a1 to a2. That line of code should be as follows: if qArray[qNbr]["answer"] contains "a2" then Objective Complete - Mini Debriefing In just 9 easy steps, we created a picture-based question type that uses images we uploaded to our stack's image library and a question set array. Your final interface should look similar to the following screenshot: Adding navigational scripting In this task, we will add scripts to the interface buttons on the Main card. Engage Thrusters Navigate to the Main card. Add the following script to the true-false button: on mouseUp set the disabled of me to true go to card "TF" end mouseUp Add the following script to the m-choice button: on mouseUp set the disabled of me to true go to card "MC" end mouseUp Add the following script to the sequence button: on mouseUp set the disabled of me to true go to card "Sequencing" end mouseUp Add the following script to the short-answer button: on mouseUp set the disabled of me to true go to card "SA" end mouseUp Add the following script to the pictures button: on mouseUp set the disabled of me to true go to card "Pictures" end mouseUp The last step in this task is to program the Reset button. Here is the code for that button: on mouseUp global theScore, totalQuestions, totalCorrect # Section 1 set the disabled of btn "true-false" to false set the disabled of btn "m-choice" to false set the disabled of btn "sequence" to false set the disabled of btn "short-answer" to false set the disabled of btn "pictures" to false # Section 2 set the backgroundColor of grc "progress1" to empty set the backgroundColor of grc "progress2" to empty set the backgroundColor of grc "progress3" to empty set the backgroundColor of grc "progress4" to empty set the backgroundColor of grc "progress5" to empty # Section3 put 0 into theScore put 0 into totalQuestions put 0 into totalCorrect put theScore & "%" into fld "Score" end mouseUp There are three sections to this code. In section 1, we are enabling each of the buttons. In the second section, we are clearing out the background color of each of the five progress circles in the bottom-center of the screen. In the final section, section 3, we reset the score and the score display. Objective Complete - Mini Debriefing That is all there was to this task, seven easy steps. There are no visible changes to the mobile application's interface. Summary In this article, we saw how to create a couple of quiz apps for mobile such as short-answer questions and picture card questions. Resources for Article: Further resources on this subject: Creating and configuring a basic mobile application [Article] Creating mobile friendly themes [Article] So, what is XenMobile? [Article]
Read more
  • 0
  • 0
  • 6022
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-basic-security-approaches
Packt
19 Sep 2013
10 min read
Save for later

Basic Security Approaches

Packt
19 Sep 2013
10 min read
(For more resources related to this topic, see here.) Security, privacy, and safeguards for intellectual property are at the front of the minds of those of us building Titanium Enterprise apps. Titanium allows you to combine the underlying platform tools and third-party JavaScript libraries to help meet your security requirements. This article provides a series of approaches on how to leverage JavaScript, Titanium modules, and the underlying platform to enable you to create a layered security approach to assist you in meeting your organization's overall secure development goals. Each recipe is designed to provide building blocks to help you implement your industry's existing security and privacy standards. Implementing iOS data protection in Titanium Starting with iOS 4, Apple introduced the ability for apps to use the data protection feature to add an additional level of security for data stored on disk. Data protection uses the built-in hardware encryption to encrypt files stored on the device. This feature is available when the user's device is locked and protected with a passcode lock. During this time, all files are protected and inaccessible until the user explicitly unlocks the device. When the device is locked, no app can access protected files. This even applies to the app that created the file. Getting ready This recipe uses the securely native module for enhanced security functionality. This module and other code assets can be downloaded from the source provided by the book. Installing these in your project is straightforward. Simply copy the modules folder into your project as shown in the following screenshot: After copying the mentioned folder, you will need to click on your tiapp.xml file in Titanium Studio and add a reference to the bencoding.securely module as shown in the following screenshot: Enabling data protection This recipe requires your iOS device to have data protection enabled. You will need a device as the simulator does not support data protection. The following steps cover how to enable this feature on your device: Go to Settings | General | Passcode . Follow the prompts to set up a passcode. After adding a passcode, scroll to the bottom of the screen and verify that the text Data protection is enabled is visible as shown in the following screenshot: iOS device browser A third-party iOS device browser is needed to verify that data protection for the example recipe app has successfully been enabled. This recipe discusses how to verify data protection using the popular iExplorer app. An evaluation version of the iExplorer app can be used to follow along with this recipe. For more information and to download iExplorer, please visit http://www.macroplant.com/iexplorer. How to do it... To enable iOS data protection, the DataProtectionClass and com.apple.developer.default-data-protection keys need to be added to your tiapp.xml as demonstrated in the following code snippet: First, add the ios configuration node if your project does not already contain this element. <ios> <plist> <dict> Then at the top of the dict node, add the following highlighted keys. <key>DataProtectionClass</key> <string>NSFileProtectionComplete</string> <key>com.apple.developer. default-data-protection</key> <string>NSFileProtectionComplete</string> </dict> </plist> </ios>   After saving the updates to your tiapp.xml, you must clean your Titanium project in order to have the updates take effect. This can be done in Titanium Studio by selecting Project | Clean . Creating the namespace and imports Once you have added the securely module and added the tiapp.xml updates to your project, you need to create your application namespace in the app.js file and use require to import the module into your code as the following code snippet demonstrates: //Create our application namespace var my = { secure : require('bencoding.securely') }; Creating the recipe UI The following steps outline how to create the UI used in this recipe: First, a Ti.UI.Window is created to attach all UI elements. var win = Ti.UI.createWindow({ backgroundColor: '#fff', title: 'Data Protection Example', barColor:'#000',layout:'vertical' }); Next, a Ti.UI.Button is added to the Ti.UI.Window. This will be used to trigger our example. var button1 = Ti.UI.createButton({ title:'Create Test File', top:25, height:45, left:5, right:5 }); win.add(button1); Creating a file to verify data protection To verify if data protection is enabled in the app, the recipe creates a time-stamped file in the Ti.Filesystem.applicationDataDirectory directory. Using an iOS device browser, we can verify if the test file is protected when the device is locked. The following steps describe how the recipe creates this test file: The click event for button1 creates a time-stamped file that allows us to verify if data protection has been correctly enabled for the app. button1.addEventListener('click',function(e){ Next the isProtectedDataAvailable method is called on securely. This provides a Boolean result indicating that data protection allows the app to read from or write to the filesystem. if(!my.secure.isProtectedDataAvailable()){ alert('Protected data is not yet available.'); return; } To ensure there is a unique identifier in the file, a token is created using the current date and time. This token is then added to the following message template: var timeToken = String.formatDate(new Date(),"medium") + String.formatTime(new Date()); var msg = "When device is locked you will not be able"; msg += " to read this file. Your time token is "; msg += timeToken; The message created in step 3 is then written to the test.txt file located in the Ti.Filesystem.applicationDataDirectory directory. If the file already exists, it is removed so that the latest message will be available for testing. var testfile = Ti.Filesystem.getFile( Ti.Filesystem.applicationDataDirectory, 'test.txt'); if(testfile.exists()){ testfile.deleteFile(); } testfile.write(msg); testfile = null; Once the test.txt file is written to the device, a message is displayed to the user notifying them to lock their device and use an iOS device browser to confirm data protection is enabled. var alertMsg = "Please lock your device."; alertMsg+= "Then open an iOS Device Browser."; alertMsg+= "The time token you are looking for is "; alertMsg+= timeToken; alert(alertMsg); How it works... After the DataProtectionClass and com.apple.developer.default-data-protection keys have been added to your tiapp.xml, the iOS device handles protecting your files when the device is locked. The following steps discuss how to test that this recipe has correctly implemented data protection: The first step in the validation process is to build and deploy the recipe app to your iOS device. Once the app has been loaded onto your device, open the app and press the Create Test File button. Once you have received an alert message indicating the test file has been created, press the home button and lock your device. Plug your device into a computer with iExplorer installed. Open iExplorer and navigate so that you can view the apps on your device. Select the DataProtection app as marked with the red box in the following screenshot. Then right-click on the test.txt file located in the Documents folder and select Quick Look as marked with the green box in the following screenshot: After Quick Look is selected, iExplorer will try to open the test.txt file. Since it is protected, it cannot be opened and Quick Look will show the progress indicator until a timeout has been reached. You can then unlock your device and repeat the preceding steps to open the file in Quick Look . AES encryption using JavaScript The Advanced Encryption Standard ( AES ) is a specification for the encryption of electronic data established by the U.S. NIST in 2001. This encryption algorithm is used for securing sensitive, but unclassified material by U.S. Government agencies. AES has been widely adopted by enterprise and has become a de facto encryption standard for many commercially sensitive transactions. This recipe discusses how AES can be implemented in JavaScript and incorporated into your Titanium Enterprise app. Getting ready This recipe uses the Ti.SlowAES CommonJS module as a wrapper around the SlowAES open source project. Installing these in your project is straightforward. Simply copy the SlowAES folder into the Resources folder of your project as shown in the following screenshot: How to do it... Once you have added the SlowAES folder to your project, next you need to create your application namespace in the app.js file and use require to import the module into your code as the following code snippet demonstrates: //Create our application namespace var my = { mod : require('SlowAES/Ti.SlowAES') }; Creating the recipe UI This recipe demonstrates the usage of the Ti.SlowAES CommonJS module through a sample app using two Ti.UI.TextField controls for input. First, a Ti.UI.Window is created to attach all UI elements. var win = Ti.UI.createWindow({ backgroundColor: '#fff', title: 'AES Crypto Example', barColor:'#000',layout:'vertical',fullscreen:false }); Next, a Ti.UI.TextField control is added to the Ti.UI.Window to gather the secret from the user. var txtSecret = Ti.UI.createTextField({ value:'DoNotTell',hintText:'Enter Secret', height:45, left:5, right:5, borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED }); win.add(txtSecret); Another Ti.UI.TextField is added to the Ti.UI.Window to gather the string to encrypt from the user. var txtToEncrypt = Ti.UI.createTextField({ value:'some information we want to encrypt', hintText:'Enter information to encrypt', height:45, left:5, right:5, borderStyle:Ti.UI.INPUT_BORDERSTYLE_ROUNDED }); win.add(txtToEncrypt); Next a Ti.UI.Label is added to the Ti.UI.Window. This Ti.UI.Label will be used to display the encrypted value to the user. var encryptedLabel = Ti.UI.createLabel({ top:10, height:65, left:5, right:5,color:'#000', textAlign:'left',font:{fontSize:14} }); win.add(encryptedLabel); Finally a Ti.UI.Button is added to the Ti.UI.Window. This Ti.UI.Button will be used later in the recipe to perform the encryption test. var btnEncrypt = Ti.UI.createButton({ title:'Run Encryption Test', top:25, height:45, left:5, right:5 }); win.add(btnEncrypt); Encrypting and decrypting values This section demonstrates how to use the Ti.SlowAES module to use the secret entered in the txtSecret, Ti.UI.TextField to encrypt the contents of the txtToEncrypt, Ti.UI.TextField. Once completed, the encrypted value is then decrypted and compared against the original input. The results are displayed to the user in an alert message as shown in the following screenshots: The encryption test is performed when the click event for the btnEncrypt control is fired as shown in the following code snippet: btnEncrypt.addEventListener('click',function(x){ The first step in the encryption process is to create a new instance of the SlowAES module as shown in this code snippet. var crypto = new my.mod(); Next using the encrypt function, the secret provided in the txtSecret control is used to encrypt the value in the txtToEncrypt control. The encrypted results are then returned to the encryptedValue as demonstrated in the following statement: var encryptedValue = crypto.encrypt(txtToEncrypt.value,txtSecret.value); The encryptedLabel.text property is then updated to display the encrypted value to the user. encryptedLabel.text = 'Encrypted:' + encryptedValue; Next, the decrypt method is used to demonstrate how to decrypt the string value encrypted earlier. This method requires the encrypted string value and the secret as shown in the following snippet: var decryptedValue = crypto.decrypt(encryptedValue,txtSecret.value); Finally, the original input value is compared against the decrypted value to ensure our encryption test was successful. The results of this test are then displayed to the user through a message alert and the Titanium Studio console. alert((txtToEncrypt.value ===decryptedValue) ? 'Encryption Test successfully ran check console for details.': 'Test failed, please check console for details.'); });
Read more
  • 0
  • 0
  • 2498

Packt
17 Sep 2013
6 min read
Save for later

Kendo UI Mobile – Exploring Mobile Widgets

Packt
17 Sep 2013
6 min read
(For more resources related to this topic, see here.) Kendo Mobile widgets basics All Kendo Mobile widgets inherit from the base class kendo.mobile.ui.Widget, which is inherited from the base class of all Kendo widgets (both Web and Mobile), kendo.ui.Widget. The complete inheritance chain of the mobile widget class is shown in the following figure: kendo.Class acts as the base class for most of the Kendo UI objects while the kendo.Observable object contains methods for events. kendo.data.ObservableObject which is the building block of Kendo MVVM, is inherited from kendo.Observable. Mobile widget base methods From the inheritance chain, all Kendo Mobile widgets inherit a set of common methods. A thorough understanding of these methods is required while building highly performing, complex mobile apps. bind The bind() method defined in the kendo.Observable class, attaches a handler to an event. Using this method we can attach custom methods to any mobile widget. The bind() method takes the following two input parameters: eventName: The name of the event handler: The function to be fired when the event is raised The following example shows how to create a new mobile widget and attach a custom event to the widget: //create a new mobile widget var mobileWidget = new kendo.mobile.ui.Widget(); //attach a custom event mobileWidget.bind("customEvent", function(e) { // mobileWidget object can be accessed inside this function as //'e.sender' and 'this'. console.log('customEvent fired'); }); The event data is available in the object e. The object which raised the event is accessible inside the function as e.sender or using the this keyword. trigger The trigger() method executes all event handlers attached to the fired event. This method has two input parameters: eventName: The name of the event to be triggered eventData (optional): The event-specific data to be passed into the event handler Let's see how trigger works by modifying the code sample provided for bind: //create a mobile widget var mobileWidget = new kendo.mobile.ui.Widget(); //attach a custom event mobileWidget.bind("customEvent", function(e) { // mobileWidget object can be accessed //inside this function as //'e.sender' and 'this' . console.log('customEvent fired'); //read event specific data if it exists if(e.eventData !== undefined){ console.log('customEvent fired with data: ' + e.eventData); } }); //trigger the event with some data mobileWidget.trigger("customEvent", { eventData:'Kendo UI is cool!' }); Here we are triggering the custom event which is attached using the bind() method and sending some data along. This data is read inside the event and written to the console. When this code is run, we can see the following output in the console: customEvent fired customEvent fired with data: Kendo UI is cool! unbind The unbind() method detaches a previously attached event handler from the widget. It takes the following input parameters: eventName: The name of the event to be detached. If an event name is not specified, all handlers of all events will be detached. handler: The handler function to be detached. If a function is not specified, all functions attached to the event will be detached. The following code attaches an event to a widget and detaches it when the event is triggered: //create a mobile widget var mobileWidget = new kendo.mobile.ui.Widget(); //attach a custom event mobileWidget.bind("customEvent", function(e) { console.log('customEvent fired'); this.unbind("customEvent"); }); //trigger the event first time mobileWidget.trigger("customEvent"); //trigger the event second time mobileWidget.trigger("customEvent"); Output: customEvent fired As seen from the output, even though we trigger the event twice, only on the first time is the event handler invoked. one The one() method is identical to the bind() method only with one exception; the handler is unbound after its first invocation. So the handler will be fired only once. To see this method in action, let's add a count variable to the existing sample code and track the number of times the handler is invoked. For this we will bind the event handler with one() and then trigger the event twice as shown in the following code: //create a mobile widget var mobileWidget = new kendo.mobile.ui.Widget(); var count = 0; //attach a custom event mobileWidget.one("customEvent", function(e) { count++; console.log('customEvent fired. count: ' + count); }); //trigger the event first time mobileWidget.trigger("customEvent"); //trigger the event second time mobileWidget.trigger("customEvent"); Output: customEvent fired. count: 1 If you replace the one() method with the bind() method, you can see that the handler will be invoked twice. destroy The destroy() method is inherited from the kendo.ui.Widget base object. The destroy() method kills all the event handler attachments and removes the widget object in the jquery.data() attribute so that the widget can be safely removed from the DOM without memory leaks. If there is a child widget available, the destroy() method of the child widget will also be invoked. Let's see how the destroy() method works using the Kendo Mobile Button widget and using your browser's developer tools' console. Create an HTML file, add the following code along with Kendo UI Mobile file references in the file, and open it in your browser: <div data-role="view" > <a class="button" data-role="button" id="btnHome" data-click="buttonClick">Home</a> </div> <script> var app = new kendo.mobile.Application(document.body); function buttonClick(e){ console.log('Inside button click event handler...'); $("#btnHome").data().kendoMobileButton.destroy(); } </script> In this code block, we created a Kendo Button widget and on the click event, we are invoking the destroy() method of the button. Now open up your browser's developer tools' Console window, type $("#btnHome").data() and press Enter . Now if you click on the Object link shown in the earlier screenshot, a detailed view of all properties can be seen: Now click on kendoMobilebutton once and then again in the Console , type $("#btnHome").data() and hit Enter . Now we can see that the kendoMobileButton object is removed from the object list: Even though the data object is gone, the button stays in the DOM without any data or events associated with it. view The view() method is specific to mobile widgets and it returns the view object in which the widget is loaded. In the previous example, we can assign an ID, mainView, to the view and then retrieve it in the button's click event using this.view().id as shown in the following code snippet: <div data-role="view" id="mainView" > <a class="button" data-role="button" id="btnHome" data-click="buttonClick">Home</a> </div> <script> var app = new kendo.mobile.Application(document.body); function buttonClick(e){ console.log("View id: " + this.view().id ); } </script> Output: View id: #mainView
Read more
  • 0
  • 0
  • 2089

article-image-android-fragmentation-management
Packt
16 Sep 2013
8 min read
Save for later

Android Fragmentation Management

Packt
16 Sep 2013
8 min read
(For more resources related to this topic, see here.) Smartphones, by now, have entered our lives not only as users and consumers but also as producers of our own content. Though this kind of device has been on the market since 1992 (the first was the Simon model by IBM), the big diffusion was driven by Apple's iPhone, when it was produced in 2007 (last year, the fifth generation of this device was released). Meanwhile, another big giant, Google, developed an open source product to be used as the internal operating system in mobile devices; in a different manner from the leader of the market, this company doesn't constraint itself to a unique hardware-specific device, but allows third-party companies to use it on their cell phones, which have different characteristics. The big advantage was also to be able to sell this device to consumers that don't want to (or can't have) spend as much money as the Apple phone costs. This allowed Android to win the battle of diffusion. But there is another side to the coin. A variety of devices by different producers means more fragmentation of the underlying system and a non-uniform user experience that can be really disappointing. As programmers, we have to take into account these problems and this article strives to be a useful guideline to solve that problem. The Android platform was born in 2003, as the product of a company which at first was known as Android Inc. and which was acquired by Google in 2005. Its direct competitors were and are still today the iOS platform by Apple and the RIM, know as Blackberry. Technically speaking, its core is an operating system using a Linux Kernel, aimed to be installed on devices with very different hardware (mainly mobile devices, but today it is also used in general embedded systems, for example, the game console OUYA that features a modified version of Android 4.0). Like any software that has been around for a while, many changes happened to the functionality and many versions came out, each with a name of a dessert: Apple Pie (API level 1) Banana Bread (API level 2) 1.5 Cupcake (API level 3) 1.6 – Donut (API level 4) 2.0-2.1x – Eclair (API level 5 to 7) 2.2 – Froyo (API level 8) 2.3 – Gingerbread (API level 9 and 10) 3.0-3.2 – Honeycomb (API level 11 to 13) 4.0 – Ice Cream Sandwich (API level 14 and 15) 4.1 – Jelly Bean (API level 16) Like in many other software projects, the names are in alphabetical order (another project that follows this approach is the Ubuntu distribution). The API level written in the parenthesis is the main point about the fragmentation. Each version of software introduces or removes features and bugs. In its lifetime, an operating system such as Android aims to add more fantastic innovations while avoiding breaking pre-installed applications in older versions, but also aims to make available to these older versions the same features with a process technically called backporting. For more information about the API levels, carefully read the official documentation available at http://developer.android.com/guide/topics/manifest/uses-sdk- element.html#ApiLevels. If you look at the diffusion of these versions as given by the following pie chart you can see there are more than 50 percent of devices have installed versions that we consider outdated with the latest; all that you will read in the article is thought to address these problems, mainly using backporting; in particular, to specifically address the backward compatibility issues with version 3.0 of the Android operating system—the version named Honeycomb. Version 3.0 was first intended to be installed on tablets, and in general, on devices with large screens. Android is a platform that from the beginning was intended to be used on devices with very different characteristics (think of a system where an application must be usable on VGA screens, with or without physical keyboards, with a camera, and so on); with the release of 3.0, all this was improved with specific APIs thought to extend and make developing applications easier, and also to create new patterns with the graphical user interfaces. The more important innovation was the introduction of the Fragment class. Earlier, the only main class in developing the Android applications was Activity, a class that provides the user with a screen in order to accomplish a specific task, but that was too coarse grain and not re-usable enough to be used in the applications with large screens such as a tablet. With the introduction of the Fragment class to be used as the basic block, it is now possible to create responsive mobile design; that is, producing content adapting to the context and optimizing the block's placement, using reflowing or a combination of each Fragment inside the main Activity. These are concepts inspired by the so called responsive web design, where developers build web pages that adapt to the viewport's size; the preeminent article about this argument is Responsive Web Design, Ethan Marcotte. For sake of completeness, let me list other new capabilities introduced with Honeycomb (look into the official documentation for a better understanding of them): Copy and Paste: A clipboard-based framework Loaders: Load data asynchronously Drag and Drop: Permits the moving of data between views Property animation framework: Supersedes the old Animation package, allowing the animation of almost everything into an application Hardware acceleration: From API level 11, the graphic pipeline uses dedicated hardware when it is present Support for encrypted storage In particular for address these changes and new features, Google make available a particular library called "Support library" that backports Fragment and Loader. Although the main characteristics of this classes are maintained, in the article is explained in detail how to use the low level API related with the threading stuff. Indeed an Android application is not a unique block of instructions executed one after the other, but is composed of multiple pipelines of execution. The main concepts here are the process and thread. When an application is started, the operating system creates a process (technically a Linux process) and each component is associated to this process. Together with the process, a thread of execution named main is also created. This is a very important thread because it is in charge of dispatching events to the appropriate user interface elements and receiving events from them. This thread is also called UI Thread. It's important to note that the system does not create a separate thread for each element, but instead uses the same UI thread for all of them. This can be dangerous for the responsiveness of your application, since if you perform an intensive or time expensive operation, this will block the entire UI. All Android developers fight against the ANR (Application Not Responding) message that is presented when the UI is not responsive for more than 5 seconds. Following Android's documentation, there are only two rules to follow to avoid the ANR: Do not block the UI thread Do not access the Android UI toolkit from outside the UI thread These two rules can seem simple, but there are some particulars that have to be clear. In the article some examples are shown using not only the Thread class (and the Runnable interface) but also the (very) low-level classes named Looper and Handler. Also the interaction between GUI elements and these classes are investigated to avoid nasty exceptions. Another important element introduced in Google's platform is the UI pattern named ActionBar—a piece of interface at the top of an application where the more important menu's buttons are visualized in order to be easily accessible. Also a new contextual menu is available in the action bar. When, for example, one or more items in a list are selected (such as, the Gmail application), the appearance of the bar changes and shows new buttons related to the actions available for the selected items. One thing not addressed by the compatibility package is ActionBar. Since this is a very important element for integration with the Android ecosystem, some alternatives are born, the first one from Google itself, as a simple code sample named ActionBar Compatibility that you can find in the sample/directory of the Android SDK. In the article, we will follow a different approach, using a famous open source project, ActionBarSherlock. The code for this library is not available from SDK, so we need to download it from its website (http://actionbarsherlock.com/). This library allows us to use the most part of the functionality of the original ActionBar implementation such as UP button (that permits a hierarchical navigation), ActionView and contextual action menu. Summary Thus in this article we learned about Android Fragmentation Management. Resources for Article : Further resources on this subject: Android Native Application API [Article] New Connectivity APIs – Android Beam [Article] So, what is Spring for Android? [Article]
Read more
  • 0
  • 0
  • 8111

article-image-creating-puzzle-app
Packt
06 Sep 2013
11 min read
Save for later

Creating a Puzzle App

Packt
06 Sep 2013
11 min read
(For more resources related to this topic, see here.) A quick introduction to puzzle games Puzzle games are a genre of video games that have been around for decades. These types of games challenge players to use logic and critical thinking to complete patterns. There is a large variety of puzzle games available, and in this article, we'll start by learning how to create a 3-by-3 jigsaw puzzle titled My Jigsaw Puzzle. In My Jigsaw Puzzle, players will have to complete a jigsaw puzzle by using nine puzzle pieces. Each puzzle piece will have an image on it, and the player will have to match the puzzle piece to the puzzle board by dragging the pieces from right to left. When the puzzle piece matches the correct location, the game will lock in the piece. Let's take a look at the final game product. Downloading the starter kit Before creating our puzzle app, you can get the starter kit for the jigsaw puzzle from the code files available with this book. The starter kit includes all of the graphics that we will be using in this article. My Jigsaw Puzzle For the Frank's Fitness app, we used Corona's built-in new project creator to help us with setting up our project. With My Jigsaw Puzzle, we will be creating the project from scratch. Although creating a project from scratch can be more time consuming, the process will introduce you to each element that goes into Corona's new project creator. Creating the project will include creating the build.settings, config.lua, main.lua, menu.lua, and gameplay.lua files. Before we can start creating the files for our project, we will need to create a new project folder on your computer. This folder will hold all of the files that will be used in our app. build.settings The first file that we will create is the build.settings file. This file will handle our device orientation and specify our icons for the iPhone. Inside our build.settings file, we will create one table named settings, which will hold two more tables named orientation and iphone. The orientation table will tell our app to start in landscape mode and to only support landscapeLeft and landscapeRight. The iphone table will specify the icons that we want to use for our app. To create the build.settings file, create a new file named build.settings in your project's folder and input the following code: settings = { orientation = { default = "landscapeRight", supported = { "landscapeLeft", "landscapeRight" }, }, iphone = { plist = { CFBundleIconFile = "Icon.png", CFBundleIconFiles = { "Icon.png", "Icon@2x.png", "Icon-72.png", } } }} config.lua Next, we will be creating a file named config.lua in our project's folder. The config.lua file is used to specify any runtime properties for our app. For My Jigsaw Puzzle, we will be specifying the width, height, and scale methods. We will be using the letterbox scale method, which will uniformly scale content as much as possible. When letterbox doesn't scale to the entire screen, our app will display black borders outside of the playable screen. To create the config.lua file, create a new file named config.lua in your project's folder and input the following code: application ={ content = { width = 320, height = 480, scale = "letterbox" }} main.lua Now that we've configured our project, we will be creating the main.lua file—the start point for every app. For now, we are going to keep the file simple. Our main. lua file will hide the status bar while the app is active and redirect the app to the next file—menu.lua. To create main.lua, create a new file named main.lua in your project's folder and copy the following code into the file: display.setStatusBar ( display.HiddenStatusBar )local storyboard = require ( "storyboard" )storyboard.gotoScene("menu") menu.lua Our next step is to create the menu for our app. The menu will show a background, the game title, and a play button. The player can then tap on the PLAY GAME button to start playing the jigsaw puzzle. To get started, create a new file in your project's folder called menu.lua. Once the file has been created, open menu.lua in your favorite text editor. Let's start the file by getting the widget and storyboard libraries. We'll also set up Storyboard by assigning the variable scene to storyboard.newScene(). local widget = require "widget"local storyboard = require( "storyboard" )local scene = storyboard.newScene() Next, we will set up our createScene() function. The function createScene() is called when entering a scene for the first time. Inside this function, we will create objects that will be displayed on the screen. Most of the following code should look familiar by now. Here, we are creating two image display objects and one widget. Each object will also be inserted into the variable group to let our app know that these objects belong to the scene menu.lua. function scene:createScene( event ) local group = self.view background = display.newImageRect( "woodboard.png", 480, 320 ) background.x = display.contentWidth*0.5 background.y = display.contentHeight*0.5 group:insert(background) logo = display.newImageRect( "logo.png", 400, 54 ) logo.x = display.contentWidth/2 logo.y = 65 group:insert(logo) function onPlayBtnRelease() storyboard.gotoScene("gameplay") end playBtn = widget.newButton{ default="button-play.png", over="button-play.png", width=200, height=83, onRelease = onPlayBtnRelease } playBtn.x = display.contentWidth/2 playBtn.y = display.contentHeight/2 group:insert(playBtn)end After the createScene() function, we will set up the enterScene() function. The enterScene() function is called after a scene has moved on to the screen. In My Jigsaw Puzzle, we will be using this function to remove the gameplay scene. We need to make sure we are removing the gameplay scene so that the jigsaw puzzle is reset and the player can play a new game. function scene:enterScene( event ) storyboard.removeScene( "gameplay" )end After we've created our createScene() and enterScene() functions, we need to set up our event listeners for Storyboard. scene:addEventListener( "createScene", scene )scene:addEventListener( "enterScene", scene ) Finally, we end our menu.lua file by adding the following line: return scene This line of code lets our app know that we are done with this scene. Now that we've added the last line, we have finished editing menu.lua, and we will now start setting up our jigsaw puzzle. gameplay.lua By now, our game has been configured and we have set up two files—main.lua and menu.lua. In our next step, we will be creating the jigsaw puzzle. The following screenshot shows the puzzle that we will be making: Getting local libraries To get started, create a new file called gameplay.lua and open the file in your favorite text editor. Similar to our menu.lua file, we need to start the file by getting in other libraries and setting up Storyboard. local widget = require("widget")local storyboard = require( "storyboard" )local scene = storyboard.newScene() Creating variables After our local libraries, we are going to create some variables to use in gameplay. lua. When you separate the variables from the rest of your code, the process of refining your app later becomes easier. _W = display.contentWidth_H = display.contentHeightpuzzlePiecesCompleted = 0totalPuzzlePieces = 9puzzlePieceWidth = 120puzzlePieceHeight = 120puzzlePieceStartingY = { 80,220,360,500,640,780,920,1060,1200 }puzzlePieceSlideUp = 140puzzleWidth, puzzleHeight = 320, 320puzzlePieces = {}puzzlePieceCheckpoint = { {x=-243,y=76}, {x=-160, y=76}, {x=-76, y=74}, {x=-243,y=177}, {x=-143, y=157}, {x=-57, y=147}, {x=-261,y=258}, {x=-176,y=250}, {x=-74,y=248}}puzzlePieceFinalPosition = { {x=77,y=75}, {x=160, y=75}, {x=244, y=75}, {x=77,y=175}, {x=179, y=158}, {x=265, y=144}, {x=58,y=258}, {x=145,y=251}, {x=248,y=247}} Here's a breakdown of what we will be using each variable for in our app: _W and _H: These variables capture the width and height of the screen. In our app, we have already specified the size of our app to be 480 x 320. puzzlePiecesCompleted: This variable is used to track the progress of the game by tracking the number of puzzle pieces completed. totalPuzzlePieces: This variable allows us to tell our app how many puzzle pieces we are using. puzzlePieceWidth and puzzlePieceHeight: These variables specify the width and height of our puzzle piece images within the app. puzzlePieceStartingY: This table contains the starting Y location of each puzzle piece. Since we can't have all nine puzzle pieces on screen at the same time, we are displaying the first two pieces and the other seven pieces are placed off the screen below the first two. We will be going over this in detail when we add the puzzle pieces. puzzlePieceSlideUp: After a puzzle piece is added, we will slide the puzzle pieces up; this variable sets the sliding distance. puzzleWidth and puzzleHeight: These variables specify the width and height of our puzzle board. puzzlePieces: This creates a table to hold our puzzle pieces once they are added to the board. puzzlePieceCheckpoint: This table sets up the checkpoints for each puzzle piece in x and y coordinates. When a puzzle piece is dragged to the checkpoint, it will be locked into position. When we add the checkpoint logic, we will learn more about this in greater detail. puzzlePieceFinalPosition: This table sets up the final puzzle location in x and y coordinates. This table is only used once the puzzle piece passes the checkpoint. Creating display groups After we have added our variables, we are going to create two display groups to hold our display objects. Display groups are simply a collection of display objects that allow us to manipulate multiple display objects at once. In our app, we will be creating two display groups—playGameGroup and finishGameGroup. playGameGroup will contain objects that are used when the game is being played and the finishGameGroup will contain objects that are used when the puzzle is complete.Insert the following code after the variables: playGameGroup = display.newGroup()finishGameGroup = display.newGroup() The shuffle function Our next task is to create a shuffle function for My Jigsaw Puzzle. This function will randomize the puzzle pieces that are presented on the right side of the screen. Without the shuffle function, our puzzle pieces would be presented in a 1, 2, 3 manner, while the shuffle function makes sure that the player has a new experience every time. Creating the shuffle function To create the shuffle function, we will start by creating a function named shuffle. This function will accept one argument (t) and proceed to randomize the table for us. We're going to be using some advanced topics in this function, but before we start explaining it, let's add the following code to gameplay.lua under our display group: function shuffle(t) local n = #t while n > 2 do local k = math.random(n) t[n] = t[k] t[k] = t[n] n = n - 1 end return tend At first glance, this function may look complex; however, the code gets a lot simpler once it's explained. Here's a line-by-line breakdown of our shuffle function. The local n = #t line introduces two new features—local and #. By using the keyword local in front of our variable name, we are saying that this variable (n) is only needed for the duration of the function or loop that we are in. By using local variables, you are getting the most out of your memory resources and practicing good programming techniques. For more information about local variables, visit www.lua.org/pil/4.2.html. In this line, we are also using the # symbol. This symbol will tell us how many pieces or elements are in a table. In our app, our table will contain nine pieces or elements. Inside the while loop, the very first line is local k = math.random(n). This line is assigning a random number between 1 and the value of n (which is 9 in our app) to the local variable k. Then, we are randomizing the elements of the table by swapping the places of two pieces within our table. Finally, we are using n = n – 1 to work our way backwards through all of the elements in the table. Summary After reading this article, you will have a game that is ready to be played by you and your friends. We learned how to use Corona's feature set to create our first business app. In My Jigsaw Puzzle, we only provided one puzzle for the player, and although it's a great puzzle, I suggest adding more puzzles to make the game more appealing to more players. Resources for Article: Further resources on this subject: Atmosfall – Managing Game Progress with Coroutines [Article] Creating and configuring a basic mobile application [Article] Defining the Application's Policy File [Article]
Read more
  • 0
  • 0
  • 9417
article-image-coding-real-time-web
Packt
30 Jul 2013
9 min read
Save for later

Coding for the Real-time Web

Packt
30 Jul 2013
9 min read
(For more resources related to this topic, see here.) As the lines between web apps and traditional desktop apps blur, our users have come to expect real-time behavior in our web apps—something that is traditionally the domain of the desktop. One cannot really blame them. Real-time interaction with data, services, and even other users has driven the connected revolution, and we are now connected in more ways than ever before. However valid this desire to be always connected and immediately informed of an event, there are inherent challenges in real-time interactions within web apps. The first challenge is that the Web is stateless. The Web is built on HTTP, a protocol that is request/response; for each request a browser makes, there is one and only one response. There are frameworks and techniques we can use to mask the statelessness of the Web, but there is no true state built into the Web or HTTP. This is further complicated as the Web is client/server. As it's stateless, a server only knows of the clients connected at any one given moment, and clients can only display data to the user based upon the last interaction with the server. The only time the client and server have any knowledge of the other is during an active request/response, and this action may change the state of the client or the server. Any change to the server's state is not reflected to the other clients until they connect to the server with a new request. It's somewhat like the uncertainty principle in that the more one tries to pin down one data point of the relationship, the more uncertain one becomes about the other points. All hope is not lost. There are several techniques that can be used to enable real-time (or near real-time) data exchange between the web server and any active client. Simulating a connected state In traditional web development, there has not been a way to maintain a persistent connection between a client browser and the web server. Web developers have gone to great lengths to try and simulate a connected world in the request/response world of HTTP. Several developers have met with success using creative thinking and loopholes within the standard itself to develop techniques such as long polling and the forever frame. Now, thanks to the realization that such a technique is needed, the organizations overseeing the next generation of web standards are also heeding the call with server-sent events and web sockets. Long polling Long polling is the default fallback for any client and server content exchange. It is not reliant on anything but HTTP—no special standards checklists or other chicanery are required. Long polling is like getting the silent treatment from your partner. You ask a question and you wait indefinitely for an answer. After some known period of time and what may seem like an eternity, you finally receive an answer or the request eventually times out. The process repeats again and again until the request is fully satisfied or the relationship terminates. So, yeah, it's exactly like the silent treatment. Forever Frame The Forever Frame technique relies on the HTTP 1.1 standard and a hidden iframe. When the page loads, it contains (or constructs) a hidden iframe used to make a request back to the server. The actual exchange between the client and the server leverages a feature of HTTP 1.1 known as Chunked Encoding. Chunked Encoding is identified by a value of chunked in the HTTP Transfer-Encoding header. This method of data transfer is intended to allow the server to begin sending portions of data to the client before the entire length of the content is known. When simulating a real-time connection between a browser and web server, the server can dispatch messages to the client as individual chunks on the request made by the iframe. Server-Sent Events Server-Sent Events (SSE) provide a mechanism for a server to raise DOM events within a client web browser. This means to use SSE, the browser must support it. As of this writing, support for SSE is minimal but it has been submitted to W3C for inclusion into the HTML5 specification. The use of SSE begins by declaring an EventSource variable: var source = new EventSource('/my-data-source'); If you then want to listen to any and all messages sent by the source, you simply treat it as a DOM event and handle it in JavaScript. source.onmessage = function(event) {// Process the event.} SSE supports the raising of specific events and complex event messaging. The message format is a simple text-based format derivative of JSON. Two newline characters separate each message within the stream, and each message may have an id, data, and event property. SSE also supports setting the retry time using the retry keyword within a message. :comment:simple messagedata:"this string is my message":complex message targeting an eventevent:thatjusthappeneddata:{ "who":"Professor Plum", "where":"Library", "with":"candlestick"} As of this writing, SSE is not supported in Internet Explorer and is partially implemented in a few mobile browsers. WebSockets The coup de grâce of real-time communication on the Web is WebSockets. WebSockets support a bidirectional stream between a web browser and web server and only leverage HTTP 1.1 to request a connection upgrade. Once a connection upgrade has been granted, WebSockets communicate in full-duplex using the WebSocket protocol over a TCP connection, literally creating a client-server connection within the browser that can be used for real-time messaging. All major desktop browsers and almost all mobile browsers support WebSockets. However, WebSocket usage requires support from the web server, and a WebSocket connection may have trouble working successfully behind a proxy. With all the tools and techniques available to enable real-time connections between our mobile web app and the web server, how does one make the choice? We could write our code to support long polling, but that would obviously use up resources on the server and require us to do some pretty extensive plumbing on our end. We could try and use WebSockets, but for browsers lacking support or for users behind proxies, we might be introducing more problems than we would solve. If only there was a framework to handle all of this for us, try the best option available and degrade to the almost guaranteed functionality of long polling when required. Wait. There is. It's called SignalR. SignalR provides a framework that abstracts all the previously mentioned real-time connection options into one cohesive communication platform supporting both web development and traditional desktop development. When establishing a connection between the client and server, SignalR will negotiate the best connection technique/technology possible based upon client and server capability. The actual transport used is hidden beneath a higher-level communication framework that exposes endpoints on the server and allows those endpoints to be invoked by the client. Clients, in turn, may register with the server and have messages pushed to them. Each client is uniquely identified to the server via a connection ID. This connection ID can be used to send messages explicitly to a client or away from a client. In addition, SignalR supports the concept of groups, each group being a collection of connection IDs. These groups, just like individual connections, can be specifically included or excluded from a communication exchange. All of these capabilities in SignalR are provided to us by two client/server communication mechanisms: persistent connections and hubs Persistent connections Persistent connections are the low-level connections of SignalR. That's not to say they provide access to the actual communication technique being used by SignalR, but to illustrate their primary usage as raw communication between client and server. Persistent connections behave much as sockets do in traditional network application development. They provide an abstraction above the lower-level communication mechanisms and protocols, but offer little more than that. When creating an endpoint to handle persistent connection requests over HTTP, the class for handling the connection requests must reside within the Controllers folder (or any other folder containing controllers) and extend the PersistentConnection class. public class MyPersistentConnection: PersistentConnection{} The PersistentConnection class manages connections from the client to the server by way of events. To handle these connection events, any class that is derived from PersistentConnection may override the methods defined within the PersistentConnection class. Client interactions with the server raise the following events: OnConnected: This is invoked by the framework when a new connection to the server is made. OnReconnected: This is invoked when a client connection that has been terminated has reestablished a connection to the server. OnRejoiningGroups: This is invoked when a client connection that has timed out is being reestablished so that the connection may be rejoined to the appropriate groups. OnReceived: This method is invoked when data is received from the client OnDisconnected: This is invoked when the connection between the client and server has been terminated. Interaction with the client occurs through the Connection property of the PersistentConnection class. When an event is raised, the implementing class can determine if it wishes to broadcast a message using Connection.Broadcast, respond to a specific client using Connection.Send, or add the client that triggered the message to a group using Connection.Groups. Hubs Hubs provide us an abstraction over the PersistentConnection class by masking some of the overhead involved in managing raw connections between client and server. Similar to a persistent connection, a hub is contained within the Controllers folder of your project but instead, extends the Hub base class. public class MyHub : Hub{} While a hub supports the ability to be notified of connection, reconnection, and disconnection events, unlike the event-driven persistent connection a hub handles the event dispatching for us. Any publicly available method on the Hub class is treated as an endpoint and is addressable by any client by name. public class MyHub : Hub{public void SendMeAMessage(string message){ /* ... */ }} A hub can communicate with any of its clients using the Clients property of the Hub base class. This property supports methods, just like the Connection property of PersistentConnection, to communicate with specific clients, all clients, or groups of clients. Rather than break down all the functionality available to us in the Hub class, we will instead learn from an example.
Read more
  • 0
  • 0
  • 2074

article-image-introducing-rubymotion-and-hello-world-app
Packt
22 Jul 2013
7 min read
Save for later

Introducing RubyMotion and the Hello World app

Packt
22 Jul 2013
7 min read
(For more resources related to this topic, see here.) If you're reading this, you're either searching for an understanding of how RubyMotion can give you the keys to make iPhone, iPad, and OS X applications, or you're simply looking for further depth in your understanding of Ruby and Objective-C development. Either way, you're in the right place. To start this journey, we need to understand the basics of these two respected, but philosophically dissimilar, technologies and how a path has been beaten between them. Starting at the base, Apple development for iOS has traditionally been handled in Objective-C. Though Apple products have grown in popularity, Objective-C has not always been the first choice for application development. There's a long and torturous road of developers who have given up their app ambitions because of Objective-C. It is clear that for the greater part of over two decades, Objective-C has generally been the only programming language choice available for apps with Apple. Objective-C was made popular by Steve Jobs' company NeXT, for licensing Objective-C from StepStone in 1988. You'll often see evidence of this in the naming conventions of fundamental objects prefixed with NS for NeXTStep/Sun. This history renders the language a business decision as much as it was ever a developer-based decision. At the time Objective-C was licensed, the Ruby programming language was just an unnamed idea in Matz's head (Yukihiro "Matz" Matsumoto, inventor of Ruby). Objective-C has evolved, grown, and survived the test of time, but it ultimately remains verbose, without standardization, and programmatically rigid. In today's world, developers can afford to be opinionated with their programming language preferences, and a lot of them choose Ruby. Ruby is a standardized, dynamic, and general object-oriented programming language that takes inspiration from a long list of successful languages. Ruby is known to support a myriad of programming paradigms and is especially known for yielding elegant code. It's also often the cool programming language. Compared to the verbose and explicit nature of Objective-C, Ruby is a far cry and extremely opinionated language that programmers often adore. Let's take a moment to identify some core differences in the syntax of these two programming languages, starting with Objective-C. Objective-C is strongly typed. Counter to what some believe, strongly typed doesn't mean you hit the keys really hard, it means your variables have restrictions in their data types and how those variables can intermix. In Objective-C this is strictly checked and handled at compile time by a .hfile, the end result being that you're usually managing at least two files to make changes in one. Though you'll often find Objective-C methods to be long and capitalized in CamelCase, Ruby clashes with a Python-styled lowercase brevity. For example: Objective-C styled method SomeObject.performSomeMethodHere Ruby styled method SomeObject.some_method It's by no accident that I've shortened the method name in the preceding example. It's actually quite common for Objective-C to have long-winded method names, while, conversely Ruby methods are to be as short as possible, while maintaining the general intention of the method. Additionally, Ruby is more likely to sample functional and meta-programming aspects to make applications simple. So, if you're wondering which of these paradigms you will need to use and be accustomed to, the answer is both! I've seen a lot of RubyMotion code, and some people simply abandon their Ruby ways to try and make their code fit in with Objective-C libraries, all with great haste. But by far, the best method I've seen, and I highly recommend, is a mix. All Objective-C and Cocoa foundation framework objects should remain CamelCase, while all Ruby remains snake_case. At first glance this seems like twice the work, but it's really next to no effort at all, as your custom objects will be all written in Ruby by you. The advantage here is that upon examination, you can tell if a function, object, or variable should be looked up online on the Apple developer site (http://developer.apple.com/library/ios/navigation/) or if it should be searched for in a local code or Ruby code (http://www.ruby-doc.org/). I kind of wish I had this benefit with other Ruby languages, since I can instantly return to an older project and distinguish which code is purely mine and which is framework. Another key diff erence is the translation of code from messages to parameterized styling. I'm going to use some of the examples from RubyMotion.com to elaborate this issue. To properly convert the Objective-C: [string drawAtPoint:point withFont:font]; You will have to simply slide everything down to the left. The parameter to string is a method on it, and the rest become parameters. This yields the following code: string.drawAtPoint(point, withFont:font) Let's start with our Hello World app now. Have the controller in place so we can break away from the lifeless shell application and move more toward a true "Hello World" app. We won't need to deal with the AppDelegateany longer. Now we can start placing code in our controller. Remember when I said that this is a framework that calls into our code at given points, here's where we choose one of those points in time to hook into, and we'll choose one of the most common UIViewControllermethods, viewDidLoad. So, create a method called viewDidLoad, and let's put the following code inside: To find out what delegates are supported by any method and the order of method calls, you can look up the class reference of the object you are extending. For example, the documentation on the UIViewControllerclass' viewDidLoadcall is identified at http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html. Running your application at this point (by typing rakein the console) will cause your application to output "Hello World" to the application's standard output (the command line in this case). There's nothing too special happening here, we're using the traditional Ruby putsmethod to give us some feedback on the console. Running this does start the simulator. To quit the simulator, you can use command+ Q or from the console window, press Ctrl+ Dor Ctrl+ C. Since our phone doesn't really have a console to receive the standard output message, let's take this up a notch by adding a label to the application and configuring it to be a more traditional Hello World" on the device. So, we plan on making a label that will have the text "Hello World", correct? Let's create the test for that. We'll start by making a new file in our specfolder called hello_world_controller_spec.rband we'll make it look like the following: Let's inspect the testing code from the previous image. Everything looks similar to the other code but, as you can see, there's no need to make a beforeblock, since we are able to access the controller by simply stating the controller we're testing on the second line. This shortcut works for any ViewController you're testing! The actual testing and use for the variable starts with our specification. We grab the label so we can apply our two requirements on the following lines. We check the text value, and verify that the label has been added to the view. This might seem quite nebulous without knowing what we're testing, but the logic is simple. We want to make sure there's a label that says "Hello World" and we want it to be visible. Running these tests will fail, which puts us on track to write the actual "Hello World" portion. You should add the following code to your project's hello_world_controller.rbfile: Summary There it is! We've finally written a real Hello World application! Congratulations on your first RubyMotion application! You deserve it! Resources for Article : Further resources on this subject: Integrating Solr: Ruby on Rails Integration [Article] Building tiny Web-applications in Ruby using Sinatra [Article] Getting started with using Chef [Article]
Read more
  • 0
  • 0
  • 2126

article-image-article-decider-external-apis
Packt
11 Jun 2013
22 min read
Save for later

The Decider: External APIs

Packt
11 Jun 2013
22 min read
(For more resources related to this topic, see here.) Using an external API APIs are provided as a service from many different companies. This is not an entirely altruistic move on the part of the company. The expectation is that by providing the information and access to the company's data, the company gets more usage for their service and more customers. With this in mind, most (if not all) companies will require you to have an account on their system in order to access their API. This allows you to access their systems and information from within your application, but more importantly from the company's perspective, it allows them to maintain control over how their data can be used. If you violate the company's usage policies, they can shut off your application's access to the data, so play nice. The API key Most APIs require a key in order to use them. An API key is a long string of text that gets sent as an extra parameter on any request you send to the API. The key is often composed of two separate pieces and it uniquely identifies your application to the system much like a username and a password would for a regular user account. As such it's also a good idea to keep this key hidden in your application so that your users can't easily get it. While each company is different, an API key is typically a matter of filling out a web form and getting the key. Most companies do not charge for this service. However, some do limit the usage available to outside applications, so it's a good idea to look at any restrictions the company sets on their service. Once you have an API key you should take a look at the available functions for the API. API functions API functions typically come in two types – public and protected: The public functions can simply be requested with the API key The protected functions will also require that a user be logged into the system in order to make the request If the API function is protected, your application will also need to know how to log in correctly with the remote system. The login functions will usually be a part of the API or a web standard such as Facebook and Google's OAuth. It should be noted that while OAuth is a standard, its implementation will vary depending on the service. You will need to consult the documentation for the service you are using to make sure that the features and functions you need are supported. Be sure to read through the service's API documentation to understand which functions you will need and if they require a login. Another thing to understand about APIs is that they don't always do exactly what you need them to do. You may find that you need to do a little more work than you expect to get the data you need. In this case, it's always good to do a little bit of testing. Many APIs offer a console interface where you can type commands directly into the system and examine the results: Image This can be really helpful for digging into the data, but consoles are not always available for every API service. Another option is to send the commands in your application (along with your API credentials) and examine the data returned in the Safari console. The drawback of this method is that the data is often returned as a single-line string that is very difficult to read as shown in the screenshot: Image This is where a tool like JSONLint comes in handy. You can copy and paste the single-line string from your Safari console into the page at http://jsonlint.com and have the string formatted so that it is much easier to read and validate the string as JSON at the same time: Image Once you get a hold of what data is being sent and received, you will need to set it all up in Sencha Touch. External APIs and Sencha Touch As we have talked about earlier in the book, you cannot use a standard AJAX request to get data from another domain. You will need to use a JSONP proxy and store to request data from an external API. Using the API or the Safari console, you can get a good idea of the data that is coming back to you and use it to set up your model. For this example, let's use a simple model called Category. code We can then set up a store to load data from the API: This will set up a store with our Category model and call the url property for our external API. Remember that we have to send our credentials along with the request so we set these as extraParams on the proxy section. The apiKey and appSecret properties shown here are examples. You will need your own API key information to use an API. We also need to set a property called rootProperty in the reader section. Most API's send back a ton of detailed information along with the request and the store needs some idea of where to start loading in the category records. We can also add additional parameters later by calling the setExtraParam() function on our store proxy. This will let us add additional parameters to be sent to our external API URL. Please note that setExtraParam() will add an additional parameter but setExtraParams() will replace all of our extraParams with the new values. The basic application The Decider application is designed to use a combination of local storage, Google's Map API, and the Foursquare API. The application will take a list of people and their food preferences, and then use Foursquare and Google Maps to find nearby places to eat that will match everyone's food preferences. This screenshot provides a pictorial representation of the preceding explanation: Image Our contacts and categories will be stored using local storage. External APIs from Google and Foursquare will generate our maps and restaurant listings respectively. We will start with a quick overview of the basic application structure and forms, before diving into the store setup and API integration. Our main container is a simple card layout: code In this viewport we will add two cards: a navigation view and a form panel. Our navigationvew will serve as our main window for display. We will add additional containers to it via our controller: code This mainView contains our navigationBar and our homeScreen container with the big Get Started button. This button will add new containers to the navigation view (we will look at this later in the controller). A DataStage project stores jobs and define their environment, such as their security and execution resources. Your project, as well as your user account, is typically created by your DataStage administrator. The second item that is added to our viewport is our form panel. This will contain text fields for first and last name, as well as a selectable list for our different food categories: code We close out the form with a segmentedbutton property, which has options for Save and Cancel. We will add the handler functions for these buttons later on in our controller. We also include a title bar at the top of the form to give the user some idea of what they are doing. One of the key pieces of this form is the categories list, so let's take a closer look at how it works. Creating the categories list Since we will be getting our list of potential restaurants from the Foursquare API, we need to use their categories as well so that we can match things up with some degree of accuracy. The Foursquare API can be found at https://developer.foursquare.com/. As mentioned before, you will need a Foursquare account to access the API. You will also need an API key in order to integrate Foursquare with your application. We can use the Foursquare's API to get a list of categories, however the API returns a list of a few hundred categories including Airports, Trains, Taxis, Museums, and Restaurants. Additionally, each of these has its own subcategories. All we really want is the subcategories for Restaurants. To make things more complicated, Foursquare's API also returns the data like this: code This means we can only get at a specific category by its order in the array of categories. For example, if Restaurants is the twenty-third category in the array, we can get to it as: categories[23], but we cannot get to it by calling categories['Restaurants']. Unfortunately, if we use categories[23] and Foursquare adds a new category or changes the order, our application will break. This is a situation where it pays to be adaptable. Foursquare's API includes a console where we can try out our API requests. We can use this console to request the data for all of our categories and then pull the data we need into a flat file for our application. Check this URL to see the output: https://developer.foursquare.com/docs/explore#req=venues/categories We can copy just the Restaurant information that we need from categories and save this as a file called categories.json and call it from our store. A better solution to this conundrum would be to write some server code that would request the full category list from Foursquare and then pull out just the information we are interested in. But for the sake of brevity, we will just use a flat json file. Each of our categories are laid out like this: code The main pieces we care about are the id, name, shortname and icon values. This gives us a data model that looks like this: code Notice that we also add a function to create an image URL for the icons we need. We do this with the convert configuration, which lets us assemble the data for image URL based on the other data in the record: code The convert function is automatically passed both the data value (v), which we ignore in this case, and the record (rec), which lets us create a valid Foursquare URL by combining the icon.prefix value, a number, and the icon.suffix value in our record. If you take a look at our previous category data example, this would yield a URL of: https://foursquare.com/img/categories_v2/food/argentinian_32.png By changing the number we can control the size of the icon (this is part of the Foursquare API as well). We combine this with our XTemplate: code This gives us a very attractive list for choosing our categories: Images Next we need to take a look at the controller for the contact form. Creating the contact controller The contact controller handles saving the contact and canceling the action. We start out the controller by declaring our references and controls: code Remember that our refs (references) provide a handy shortcut we can use anywhere in the controller to get to the pieces we need. Our control section attaches tap listeners to our cancel and save buttons. Next we need to add our two functions after the controls section. The doCancel function is really simple: code We just use our references to clear the contact editor, deselect all the items in our category list, and switch back to our main view. The save function is a little more complex, but similar to the functions we have covered elsewhere in this book: code As with our previous save functions, we create a new MyApp.model.Contact and add the values from our form. However, since our list isn't really a standard form component we need to grab its selections separately and add them to the contact data as a comma-separated list. We do this by creating an empty array and using Ext.each() to loop through and run a function on all our categories. We then use join to implode the array into a comma-separated list. Finally, we save the contact and run our doCancel function to clean up and return to our main view. Now that we can add contacts we need to create a controller to handle our requests to the Foursquare and Google APIs, and get the data back to our users. Integrating with Google Maps and Foursquare Our application still has a couple of tasks to accomplish. It needs to: Handle the click of the Get Started button Add our maps panel and offer to adjust the current location via Google Maps API Display a list of friends to include in our search Display the search results in a list Display the details for a selected result We will start out with the basic skeleton of the controller, create the views and stores, and then finish up the controller to complete the application. Starting the mainView.js controller We will start the mainView.js controller file with some placeholders for the stores. We will add views later on and some references for those components. Keep in mind that when working with placeholders in this fashion the application will not be testable until all the files are actually in place. We create the mainView.js file in our controllers folder: code At the top of this configuration we require Ext.DateExtras. This file provides us with formatting options for date objects. If this file is not included, only the now() method for date objects will be available in your application. In our views section we have added placeholders for confirmLocation, restaurantList, friendChooser,and restaurantDetails. We will add these files later on, along with the RestaurantStore file listed in our stores section. We also have a number of references for these views, stores, and some of their sub-components. We will need to create these views before getting to the rest of our controller. We will take these views in the order the user will see them, starting with the confirmLocation view. Creating the confirmLocation view The confirmLocation view first appears when the user clicks on the Get Started button. This view will present the user with a map showing their current location and offer an option to switch to a different location if the user desires. The following screenshot gives a pictorial representation of the preceding code: Image In order to give ourselves a bit more flexibility, we will be using the Google Maps Tracker plugin as part of this view. You can find this plugin in your Sencha Touch 2 folder in examples/map/lib/plugin/google/Tracker.js. Copy the file into a lib/google folder in your main application folder and be sure to add it into the requires section of your app.js file: code This plugin will let us easily drop markers on the map. Once the Google Tracker plugin file is included in the application, we can set up our confirmLocation.js view like so: code The view itself is a simple container with some HTML at the top asking the user to confirm their location. Next we have a map container that uses our Google Tracker plugin to configure the map and animate the location marker to drop from the top of the screen to the current location of the user. The position configuration is a default location, which is used when the user denies the application access to their current location. This one is set to the Sencha Headquarters. Next we need a few options for the user to choose from: Cancel, New Location, and Next. We will add these as a segmented button under our map container. We add the code to the end of our items container (after the map container): code Each of our buttons has an associated action. This allows us to assign functions to each button within the mainView.js controller. By creating buttons in this fashion, we maintain separation between the display of the application and the functionality of the application. This is really helpful when you want to re-use a view component. The next view the user encounters is the Friends Chooser. Creating the Friends Chooser view The friendsChooser.js file uses a similar list to our previous category chooser. This lets our users select multiple people to include in the restaurant search: Image Our friendChooser extends the Ext.Container component and allows the user to select from a list of friends: code As with our previous panel, we have a container with HTML at the top to provide some instructions to the user. Below that is our list container, which, like our category list, allows for selection of multiple items via the mode: 'MULTI' configuration. We also set grouped to true. This allows our store to group the contacts together by last name. If you take a look at the ContactStore.js file, you can see where we do: code This configuration returns the first letter of the last name for grouping. The last thing we need to do with our friendChooser.js file is add the buttons at the bottom to Cancel or Finish the search. The buttons go out in the items section, just below the list: code As in our previous view, we use a segmentedbutton property with actions assigned to each of our individual buttons. Once the user clicks on Finish, we will need to return a list of restaurants they can select from. Creating the restaurant list, store, and details Our restaurant list will use a store and the Foursquare API to return a list of restaurants based on the shared preferences of everyone the user selected. The following screenshot exemplifies the preceding explanation: Image This component is pretty basic: code This component uses a simple list with a configuration option for onItemDisclosure:true. This places an arrow next to the restaurant name in the list. The user will be able to click on the arrow and see the details for that restaurant (which we will create after the store). We also set grouped to true, only this time our store will use a function to calculate and sort by distance. Creating the restaurant store and model The restaurant store is where we set up our request to the Foursquare API: code The RestaurantStore.js file sets a model and storeId field for our store and then defines our proxy. The proxy section is where we set up our request to Foursquare. As we mentioned at the start of the article, this needs to be a jsonp request since it is going to another domain. We make our request to https://api.foursquare. com/v2/venues/search and we are looking for the responses.venues section of the JSON array that gets returned. You will note that this store currently has no other parameters to send to Foursquare. We will add these later on in the controller before we load the store. For the model, we can consult the Foursquare API documentation to see the information that is returned for a restaurant (called a venue in Foursquare terms) at https://developer.foursquare.com/docs/responses/venue You can include any of the fields listed on the page. For this app, we have chosen to include the following code in our model: code You can add more fields if you want to display more information in the details view. Creating the details view The details view is a simple panel and XTemplate combination. Using our controller, the panel will receive the data record when a user clicks on a restaurant in the list: code Since the tpl tag is basically HTML, you can use any CSS styling you like here. Keep in mind that certain fields such as contact, location, and categories can have more than one entry. You will need to use <tpl for="fieldname"> to loop through these values. Now that the views are complete, we need to head back to our controller and add the functions to put everything together. Finishing the main view controller When we started out with our main controller, we added all of our views, stores, and references. Now it's time to add the functionality for the application. We start by adding a control section to the end of our config: code The controls are based on the references in the controller and they add functions to specific listeners on the component. These are each in the format of: code Once these controls are in place, we can add our functions after the config section of our controller. Our first function is doStart. This function loads our Contacts store and checks to see if we have any existing contacts. If not, we alert the user and offer to let them add some. If they have contacts we create a new instance of our confirmLocation container and push it onto the main navigation view: code Remember that since the mainView is a navigation view, a Back button will automatically be created in the top toolbar. This function will show the user our initial map panel with the users current location. This panel needs four functions: one to cancel the request, one to pop up a new location window, one to set the new location, and one to move on to the next step: code We actually want to be able to use the doCancel function from anywhere in the process. As we add new panels to our mainView navigation, these panels simply pile up in a stack. This means we need to get the number of panels currently on the mainView stack. We use length-1 to always leave the initial panel (the one with our big Get Started button) on the stack. We use pop to remove all but the first panel from the stack. This way the Cancel button will take us all the way back to the beginning of our stack, while the Back button will take us back just to the previous step. The next function is doNewLocation(), which uses Ext.Msg.prompt to ask the user to enter a new location: code If the user enters a new location, we call setNewLocation to process the text the user entered in the prompt textbox: code This code gets our map and encodes the text the user passed us as a geocode location. If Google returns a valid address, we center the map on the location and drop a marker to show the exact location. We also set the latitude and longitude so that we can reference them later. If we fail to get a valid address, we alert the user so they can fix it and try again. Once the user is happy with the location they can click on the Next button, which fires our doChooseFriends function: This function pushes our friendchooser view onto the stack for display. The friendchooser view allows the user to select multiple friends and click on Cancel or Finish. Since we have already taken care of our Cancel button with our doCancel function, we just need to write the doShowRestaurants function. This function starts by looping through the selected friends. For the first one in the list, we grab the restaurant categories we have stored for the friend and convert it from a comma-separated list (which is how we stored it) into an array. This lets us grab every subsequent selection and run Ext.Array.intersect() to find the common categories between all of the selected friends: code Next, we load the store based on the common categories by categoryID, the location data we have stored in our map, client_id, and client_secret that comprise our API key for Foursquare and a radius value (in meters). We also send a required field called v that is set to the current date. Finally, we push our restaurant list component onto the stack of containers. This will display our list of results and allow the user to click on for details. This brings us to our doShowRestaurantDetails function: code When the user taps one of the disclosure icons in our list of restaurants, we push a restaurantdetails view onto the stack of containers and set its data to the record that was tapped. This displays the details for the restaurant in our details XTemplate Homework There are a number of additional features that can be added to this type of application, including: Editing for contacts (or automatically pulling friends from Facebook) Setting up a live feed for the categories menu Adding additional venues other than restaurants Combining the application with additional APIs such as Yelp for reviews Just remember the key requirements of using additional APIs: the API key(s), studying the API documentation, and using the JSONP store for grabbing the data. Summary In this article we talked about using external APIs to enhance your Sencha Touch applications. This included: An overview of API basics Putting together the basic application Interaction with Google Maps and Foursquare Building the views, models, and stores Building the application controller Resources for Article : Further resources on this subject: How to Use jQuery Mobile Grid and Columns Layout [Article] iPhone JavaScript: Installing Frameworks [Article] An Introduction to Rhomobile [Article]
Read more
  • 0
  • 0
  • 4027
article-image-qr-codes-geolocation-google-maps-api-and-html5-video
Packt
07 Jun 2013
9 min read
Save for later

QR Codes, Geolocation, Google Maps API, and HTML5 Video

Packt
07 Jun 2013
9 min read
(For more resources related to this topic, see here.) QR codes We love our smartphones. We love showing off what our smartphones can do. So, when those cryptic squares, as shown in the following figure, started showing up all over the place and befuddling the masses, smartphone users quickly stepped up and started showing people what it's all about in the same overly-enthusiastic manner that we whip them out to answer even the most trivial question heard in passing. And, since it looks like NFC isn't taking off anytime soon, we'd better be familiar with QR codes and how to leverage them. The data shows that knowledge and usage of QR codes is very high according to surveys:(http://researchaccess.com/2012/01/new-data-on-qrcode-adoption/) More than two-thirds of smartphone users have scanned a code More than 70 percent of the users say they'd do it again (especially for a discount) Wait, what does this have to do with jQuery Mobile? Traffic. Big-time successful traffic. A banner ad is considered successful if only two percent of people lick through (http://en.wikipedia.org/wiki/Clickthrough_rate). QR codes get more than 66 percent! I'd say it's a pretty good way to get people to our reations and, thus, should be of concern. But QR codes are for more than just URLs. Here we have a URL, a block of text, a phone number, and an SMS in the following QR codes: There are many ways to generate QR codes (http://www.the-qrcode-generator.com/, http://www.qrstuff.com/). Really, just search for QR Code Generator on Google and you'll have numerous options. Let us consider a local movie theater chain. Dickinson Theatres (dtmovies.com) has been around since the 1920s and is considering throwing its hat into the mobile ring. Perhaps they will invest in a mobile website, and go all-out in placing posters and ads in bus stops and other outdoor locations. Naturally, people are going to start scanning, and this is valuable to us because they're going to tell us exactly which locations are paying off. This is really a first in the advertising industry. We have a medium that seems to spur people to interact on devices that will tell us exactly where they were when they scanned it. Geolocation matters and this can help us find the right locations. Geolocation When GPS first came out on phones, it was pretty useless for anything other than police tracking in case of emergencies. Today, it is making the devices that we hold in our hands even more personal than our personal computers. For now, we can get a latitude, longitude, and timestamp very dependably. The geolocation API specification from the W3C can be found at http://dev.w3.org/geo/api/spec-source.html. For now, we'll pretend that we have a poster prompting the user to scan a QR code to find the nearest theater and show the timings. It would bring the user to a page like this: Since there's no better first date than dinner and a movie, the movie going crowd tends to skew a bit to the younger side. Unfortunately, that group does not tend to have a lot of money. They may have more feature phones than smartphones. Some might only have very basic browsers. Maybe they have JavaScript, but we can't count on it. If they do, they might have geolocation. Regardless, given the audience, progressive enhancement is going to be the key. The first thing we'll do is create a base level page with a simple form that will submit a zip code to a server. Since we're using our template from before, we'll add validation to the form for anyone who has JavaScript using the validateMe class. If they have JavaScript and geolocation, we'll replace the form with a message saying that we're trying to find their location. For now, don't worry about creating this file. The source code is incomplete at this stage. This page will evolve and the final version will be in the source package for the article in the file called qrresponse. php as shown in the following code: <?php $documentTitle = "Dickinson Theatres"; $headerLeftHref = "/"; $headerLeftLinkText = "Home"; $headerLeftIcon = "home"; $headerTitle = ""; $headerRightHref = "tel:8165555555"; $headerRightLinkText = "Call"; $headerRightIcon = "grid"; $fullSiteLinkHref = "/"; ?> <!DOCTYPE html> <html> <head> <?php include("includes/meta.php"); ?> </head> <body> <div id="qrfindclosest" data-role="page"> <div class="logoContainer ui-shadow"></div> <div data-role="content"> <div id="latLong> <form id="findTheaterForm" action="fullshowtimes.php" method="get" class="validateMe"> <p> <label for="zip">Enter Zip Code</label> <input type="tel" name="zip" id="zip" class="required number"/> </p> <p><input type="submit" value="Go"></p> </form> </div> <p> <ul id="showing" data-role="listview" class="movieListings" data-dividertheme="g"> </ul> </p> </div> <?php include("includes/footer.php"); ?> </div> <script type="text/javascript"> //We'll put our page specific code here soon </script> </body> </html> For anyone who does not have JavaScript, this is what they will see, nothing special. We could spruce it up with a little CSS but what would be the point? If they're on a browser that doesn't have JavaScript, there's pretty good chance their browser is also miserable at rendering CSS. That's fine really. After all, progressive enhancement doesn't necessarily mean making it wonderful for everyone, it just means being sure it works for everyone. Most will never see this but if they do, it will work just fine For everyone else, we'll need to start working with JavaScript to get our theater data in a format we can digest programmatically. JSON is perfectly suited for this task. If you are already familiar with the concept of JSON, skip to the next paragraph now. If you're not familiar with it, basically, it's another way of shipping data across the Interwebs. It's like XML but more useful. It's less verbose and can be directly interacted with and manipulated using JavaScript because it's actually written in JavaScript. JSON is an acronym for JavaScript Object Notation. A special thank you goes out to Douglas Crockford (the father of JSON). XML still has its place on the server. It has no business in the browser as a data format if you can get JSON. This is such a widespread view that at the last developer conference I went to, one of the speakers chuckled as he asked, "Is anyone still actually using XML?" { "theaters":[ { "id":161, "name":"Chenal 9 IMAX Theatre", "address":"17825 Chenal Parkway", "city":"Little Rock", "state":"AR", "zip":"72223", "distance":9999, "geo":{"lat":34.7684775,"long":-92.4599322}, "phone":"501-821-2616" }, { "id":158, "name":"Gateway 12 IMAX Theatre", "address":"1935 S. Signal Butte", "city":"Mesa", "state":"AZ", "zip":"85209", "distance":9999, "geo":{"lat":33.3788674,"long":-111.6016081}, "phone":"480-354-8030" }, { "id":135, "name":"Northglen 14 Theatre", "address":"4900 N.E. 80th Street", "city":"Kansas City", "state":"MO", "zip":"64119", "distance":9999, "geo":{"lat":39.240027,"long":-94.5226432}, "phone":"816-468-1100" } ] } Now that we have data to work with, we can prepare the on-page scripts. Let's put the following chunks of JavaScript in a script tag at the bottom of the HTML where we had the comment: We'll put our page specific code here soon //declare our global variables var theaterData = null; var timestamp = null; var latitude = null; var longitude = null; var closestTheater = null; //Once the page is initialized, hide the manual zip code form //and place a message saying that we're attempting to find //their location. $(document).on("pageinit", "#qrfindclosest", function(){ if(navigator.geolocation){ $("#findTheaterForm").hide(); $("#latLong").append("<p id='finding'>Finding your location...</ p>"); } }); //Once the page is showing, go grab the theater data and find out which one is closest. $(document).on("pageshow", "#qrfindclosest", function(){ theaterData = $.getJSON("js/theaters.js", function(data){ theaterData = data; selectClosestTheater(); }); }); function selectClosestTheater(){ navigator.geolocation.getCurrentPosition( function(position) { //success latitude = position.coords.latitude; longitude = position.coords.longitude; timestamp = position.timestamp; for(var x = 0; x < theaterData.theaters.length; x++) { var theater = theaterData.theaters[x]; var distance = getDistance(latitude, longitude, theater.geo.lat, theater.geo.long); theaterData.theaters[x].distance = distance; }} theaterData.theaters.sort(compareDistances); closestTheater = theaterData.theaters[0]; _gaq.push(['_trackEvent', "qr", "ad_scan", (""+latitude+","+longitude) ]); var dt = new Date(); dt.setTime(timestamp); $("#latLong").html("<div class='theaterName'>" +closestTheater.name+"</div><strong>" +closestTheater.distance.toFixed(2) +"miles</strong><br/>" +closestTheater.address+"<br/>" +closestTheater.city+", "+closestTheater.state+" " +closestTheater.zip+"<br/><a href='tel:" +closestTheater.phone+"'>" +closestTheater.phone+"</a>"); $("#showing").load("showtimes.php", function(){ $("#showing").listview('refresh'); }); }, function(error){ //error switch(error.code) { case error.TIMEOUT: $("#latLong").prepend("<div class='ui-bar-e'> Unable to get your position: Timeout</div>"); break; case error.POSITION_UNAVAILABLE: $("#latLong").prepend("<div class='ui-bar-e'> Unable to get your position: Position unavailable</div>"); break; case error.PERMISSION_DENIED: $("#latLong").prepend("<div class='ui-bar-e'> Unable to get your position: Permission denied. You may want to check your settings.</div>"); break; case error.UNKNOWN_ERROR: $("#latLong").prepend("<div class='ui-bar-e'> Unknown error while trying to access your position.</div>"); break; } $("#finding").hide(); $("#findTheaterForm").show(); }, {maximumAge:600000}); //nothing too stale } The key here is the function geolocation.getCurrentPosition, which will prompt the user to allow us access to their location data, as shown here on iPhone If somebody is a privacy advocate, they may have turned off all location services. In this case, we'll need to inform the user that their choice has impacted our ability to help them. That's what the error function is all about. In such a case, we'll display an error message and show the standard form again.
Read more
  • 0
  • 0
  • 7224

article-image-cloud-enabling-your-apps
Packt
08 May 2013
7 min read
Save for later

Cloud-enabling Your Apps

Packt
08 May 2013
7 min read
(For more resources related to this topic, see here.) Which cloud services can you use with Titanium? Here is a comparison of the services offered by three cloud-based providers who have been proven to work with Titanium: Appcelerator Cloud Services Parse StackMob Customizable storage Yes Yes Yes Push notifications Yes Yes Yes E-mail Yes No No Photos Yes Yes Yes Link with Facebook/Twitter account Yes Yes Yes User accounts Yes Yes Yes The services offered by these three leading contenders are very similar. The main difference is the cost. Which is the best one for you? It depends on your requirements; you will have to do the cost/benefit analysis to work out the best solution for you. Do you need more functionality than this? No problem, look around for other PaaS providers. The PaaS service offered by RedHat has been proven to integrate with Titanium and offers far more flexibility. There is an example of a Titanium app developed with RedHat Openshift at https://openshift.redhat.com/community/blogs/developing-mobile-appsfor-the-cloud-with-titanium-studio-and-the-openshift-paas It doesn't stop there; new providers are coming along almost every month with new and grand ideas for web and mobile integration. My advice would be to take the long view. Draw up a list of what you require initially for your app and what you realistically want in the next year. Check this list against the cloud providers. Can they satisfy all your needs at a workable cost? They should do; they should be flexible enough to cover your plans. You should not need to split your solution between providers. Clouds are everywhere Cloud-based services offer more than just storage. Appcelerator Cloud Services Appcelerator Cloud Services ( ACS) is well integrated into Titanium. The API includes commands for controlling ACS cloud objects. In the first example in this article we are going to add commentary functionality to the simple forex app. Forex commentary is an ideal example of the benefits of cloud-based storage where your data is available across all devices. First, let's cover some foreground to the requirements. First, let's cover some foreground to the requirements. The currency markets are open 24 hours a day, 5 days a week and trading opportunities can present themselves at any point. You will not be in front of your computer all of the time so you will need to be able to access and add commentary when you are on your phone or at home on your PC. This is where the power of the cloud really starts to hit home. We already know that you can create apps for a variety of devices using Appcelerator. This is good; we can access our app from most phones, but now using the cloud we can also access our commentary from anywhere. So, comments written on the train about the EURUSD rate can be seen later when at home looking at the PC. When we are creating forex commentary, we will store the following: The currency pair (that is EURUSD) ‹ The rate (the current exchange rate) The commentary (what we think about the exchange rate) We will also store the date and time of the commentary. This is done automatically by ACS. All objects include the date they were created. ACS allows you to store key value pairs (which is the same as Ti.App.Properties), that is AllowUserToSendEmails: True, or custom objects. We have several attributes to our commentary post so a key value pair will not suffice. Instead we will be using a custom object. We are going to add a screen that will be called when a user selects a currency. From this screen a user can enter commentary on the currency. Time for action – creating ACS custom objects Perform the following steps to create ACS custom objects: Enable ACS in your existing app. Go to tiapp.xml and click on the Enable... button on the Cloud Services section. Your project will gain a new Ti.Cloud module and the ACS authentication keys will be shown: Go to the cloud website, https://my.appcelerator.com/apps, find your app, and select Manage ACS. Select Development from the selection buttons at the top. You need to define a user so your app can log in to ACS. From the App Management tab select Users from the list on the right. If you have not already created a suitable user, do it now. We will split the functionality in this article over two files. The first file will be called forexCommentary.js and will contain the cloud functionality, and the second file called forexCommentaryView.js will contain the layout code. Create the two new files. Before we can do anything with ACS, we need to log in. Create an init function in forexCommentary.js which will log in the forex user created previously: function init(_args) { if (!Cloud.sessionId) { Cloud.Users.login({ login: 'forex', password: 'forex' }, function (e) { if (e.success) { _args.success({user : e.users[0]}); } else { _args.error({error: e.error}); } }); } This is not a secure login, it's not important for this example. If you need greater security, use the Ti.Cloud.Users. secureLogin functionality. Create another function to create a new commentary object on ACS. The function will accept a parameter containing the attribute's pair, rate, and commentary and create a new custom object from these. The first highlighted section shows how easy it is to define a custom object. The second highlighted section shows the custom object being passed to the success callback when the storage request completes: function addCommentary(_args) { // create a new currency commentary Cloud.Objects.create({ classname: className, fields: { pair: _args.pair, rate: _args.rate, comment: _args.commentary } }, function (e) { if (e.success) { _args.success(e.forexCommentary[0]); } else { _args.error({error: e.error}); } }); } Now to the layout. This will be a simple form with a text area where the commentary can be added. The exchange rate and currency pair will be provided from the app's front screen. Create a TextArea object and add it to the window. Note keyboardType of Ti.UI.KEYBOARD_ASCII which will force a full ASCII layout keyboard to be displayed and returnKeyType of Ti.UI.RETURNKEY_DONE which will add a done key used in the next step: var commentary = Ti.UI.createTextArea({ borderWidth:2, borderColour:'blue', borderRadius:5, keyboardType: Ti.UI.KEYBOARD_ASCII, returnKeyType: Ti.UI.RETURNKEY_DONE, textAlign: 'left', hintText: 'Enter your thoughts on '+thePair, width: '90%', height : 150 }); mainVw.add(commentary); Now add an event listener which will listen for the done key being pressed and when triggered will call the function to store the commentary with ACS: commentary.addEventListener('return', function(e) {forex.addCommentary({ pair: thePair, rate: theRate, commentary: e.value}) }); Finally add the call to log in the ACS user when the window is first opened: var forex = require('forexCommentary'); forex.init(); Run the app and enter some commentary. What just happened? You created functions to send a custom defined object to the server. Commentary entered on the phone is almost immediately available for viewing on the Appcelerator console (https://my.appcelerator.com/apps) and therefore available to be viewed by all other devices and formats. Uploading pictures Suppose you want to upload a picture, or a screenshot? This next example will show how easy it is to upload a picture to ACS.
Read more
  • 0
  • 0
  • 2205