Thursday, March 27, 2014

Journey to App - Part 6 - Down to Coding

Well it has been almost a month, and I have been working on the app and wanted to update you on the progress.  From a functionality perspective, it doesn't look much different from the prototyped App in Parts 4 and 5 of the series, however, this is where the more tedious coding takes place, to turn the prototype into a release ready app.

Overall I would place the App in a "beta" state (with the exception of graphical assets).  To get there from the prototyp state of the app, here are the important elements that I have been working on:

  • Usability
  • Navigation
  • Presentation
  • Internationalization (support for multiple languages)
  • Error trapping and robustness
  • Support functions (email for help, privacy policy, acknowledgements)
  • Code factoring (and re-factoring)
  • Device Testing
I will offer some brief comments on each of these.

Usability
With the functionality prototyped, It is important to spend some time thinking about usability.  For example, I noticed that when there are no documents, and the user starts the App, they are presented with a blank screen.  I imagine that would be quite confusing to a user, so I added a new screen that provides some help, and also allows the user to enter a URL to convert to a PDF.  The screenshot below shows the new screen.


In addition to the new screen for converting a document, the prototype was not providing the user with any control over the conversion process.  So I created a screen that provides the ability for the user to change the file name of the PDF, as well as choose either Letter or A4 paper size (as a factor of internationalization, it is important to remember only the US and a few other countries use Letter sized paper, the rest of the world uses A4).  This screen is show below.



An additional usability feature is to allow the user to see what the current URL is in the main web browser.  This is a small detail, but provides feedback to the users, and is worth the effort to add to the App.

Navigation
The prototype had the basic navigation that the app needed, but there were some adjustments that needed to be made.  Upon startup, the App needs to detect the number of PDF documents.  If there are PDF files, the App should start in the PDF Documents screen, if not, it needs to start in the Convert screen.  Also, the navigation between screens needed to be adjusted.  In the prototype, the slide menu worked just fine, but the back arrows were causing problems with the app leaving artifacts (not intended screens) that were unexpected.

In general, you should run through all of the screens on your app, as you anticipate the user may.  Make sure that you perform all the different actions that the user can do, and make sure that you get expected results, and that the results make sense.

Presentation
By presentation, what I mean is how each screen looks ... the fonts that are chosen, the size of the fonts, the use of space.  This can be a tough aspect of App development, as "beauty is often in the eye of the beholder", so what looks go to you may not look good to others  In Appcelerator Titanium, when using the Alloy MVC framework, you can separate out the presentation aspects of the file from the layout and the code.  This is particularly helpful, as it makes it very easy to focus on different elements of your app at different times.  In the classic version of Titanium, the presentation settings were intermixed with the layout and with the programming.  This made it difficult to quickly adjust any of those three components.  With Alloy, the presentation elements are handled in a CSS style sheet like file (called a "TSS" file).

Internationalization
If you want your App to do well in other countries, you should consider putting in the effort to have the text elements translated.  Although you app will still be downloaded in other countries if it is only in english, adding other languages can help your success.  With Appcelerator Titanium, internationalizing your app is easy.  Titanium supports XML files where you can put in text "snippets".  You create one XML file for each supported language, and in your code you can extract the appropriate language specific text by using the following function:   L("textKey", "Some Default Text if Key is not found").  For this app, here is my English XML File:


<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="language">en-us</string>
<string name="cancel">Cancel</string>
<string name="ok">OK</string>
<string name="go">Go</string>
<string name="or">or</string>
<string name="save">Save</string>
<string name="letter">Letter</string>
<string name="a4">A4</string>
<string name="acknowledged">Acknowledged</string>
<string name="application">Go PDF</string>
<string name="titlePDFDocuments">PDF Documents</string>
<string name="titleURLHistory">URL History</string>
<string name="titleConvertToPDF">Convert to PDF</string>
<string name="titleOpenInSafari">Open in Safari</string>
<string name="titleConvertAPage">Convert a Web Page to PDF</string>
<string name="titleSettings">Settings</string>
<string name="titlePDFFiles">PDF Files</string>
<string name="titleHistory">History</string>
<string name="titleUnexpectedError">Unexpected Error</string>
<string name="titleGotoDocs">My Documents</string>
<string name="titleFileName">File Name</string>
<string name="titleSaveToFilename">Enter file name for the PDF</string>
<string name="textTypeOrPaste">Type or paste a web address</string>
<string name="titleEnterAddress">Enter URL</string>
<string name="titlePaperType">Paper Type</string>
<string name="textConvertFromSafari">To convert a web page directly from Safari:</string>
<string name="textPDFColon">Change http:// to either pdf:// or pdfhttp://</string>
<string name="textPDFSColon">Change https:// to either pdfs:// or pdfhttps://</string>
<string name="textDocumentsCreated">%d PDF Documents Created!</string>
<string name="titleFileWarning">This file exists and will be overwritten!</string>
</resources>

As you can see, this is pretty straight forward, with an XML node for each piece of text you need to change.

Obviously the best way to have this translated into other languages is to have a native speaker translate it for you.  You can do that with many services out there.  For the amount above, it will cost about $15 per language. 

For this project, I chose machine translation.  You can use http://translate.google.com which is pretty good, but you have to translate small chunks of text.  Alternatively, I like to use https://translate.google.com/toolkit/ which allows you to upload a file and manage your translations.  I created a simple XLS file that will strip out the XML tags so you can upload just the elements to be translated.  After translation, you can place the translated elements back into the spreadsheet, and it will reconstruct the XML.  I will post the file as soon as I find a good place.

For the blog series, I only translated to French.  Here is the french XML.  (Please post a comment if any of the translations are not correct!!).


<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="language">fr-fr</string>
<string name="cancel">Annuler</string>
<string name="ok">Accepter</string>
<string name="go">Go</string>
<string name="or">ou</string>
<string name="save">Sauvegarder</string>
<string name="letter">Lettre</string>
<string name="a4">A4</string>
<string name="acknowledged">Reconnu</string>
<string name="application">Go PDF</string>
<string name="titlePDFDocuments">Documents PDF</string>
<string name="titleURLHistory">Histoire d'URL</string>
<string name="titleConvertToPDF">Convertir en PDF</string>
<string name="titleOpenInSafari">Ouvrir dans Safari</string>
<string name="titleConvertAPage">Convertir une page Web en PDF</string>
<string name="titleSettings">Réglages</string>
<string name="titlePDFFiles">Fichiers PDF</string>
<string name="titleHistory">Historique</string>
<string name="titleUnexpectedError">Erreur Inattendue</string>
<string name="titleGotoDocs">Mes Documents</string>
<string name="titleFileName">Nom du Fichier</string>
<string name="titleSaveToFilename">Entrez un nom de fichier pour le PDF</string>
<string name="textTypeOrPaste">Tapez ou collez une adresse Web</string>
<string name="titleEnterAddress">Entrez URL</string>
<string name="titlePaperType">Type de papier</string>
<string name="textConvertFromSafari">Pour convertir une page web directement depuis Safari:</string>
<string name="textPDFColon">Changer http:// soit pdf :// ou pdfhttp ://</string>
<string name="textPDFSColon">Changer https:// soit pdfs :// ou pdfhttps ://</string>
<string name="textDocumentsCreated">%d documents PDF créés!</string>
<string name="titleFileWarning">Ce fichier existe et sera remplacé!</string>
</resources>

Once you have your translations, switch the language on your phone and look at how Apple changes Apps, such as settings to see if you are using the correct word (I know google translates setting to Paramètres, where Apple uses Réglages)

Error trapping and robustness
With every new app, some bugs are inevitable (based on reasonable testing), but there are techniques to reduce the impact of those errors on the user.  In general, you should test all the functions of your app, and most importantly, test your app in unintended ways.  If you have access to a 4 year old, they make good testers, but if not, use your imagination. 

In addition you can use coding techniques, such as a try ... catch statement to reduce the impact of any errors on your users.  I find this technique to be especially important if you are doing anything with internet communications, where you cannot control all aspects of the program's execution.

Here is an example from the app of a simple try ... catch statement.

try {
   //Create a FileManager object
   var fm = new FileManager();
   var results = fm.ls(Alloy.Globals.directoryPath);
   return (results.fileCount > 0) ? true : false;
} catch(err) {
   handleError({
      f : 'functions.filesExists',
      err : err
   });
}

The instructions in the try portion of the statement are executed, and if an error happens, the catch portion traps the error and, in this case, I pass it to a generic function to address the error.

Support Functions
All users need a little help some times, so make sure you provide it.  Typically a settings or "about this app" screen that provides some information about the app, as well as a way to contact you for support.  The Chariti app framework includes a "settings" screen that provides links for your Apps Terms of Use, Privacy Policy and Email Support functions.  

For the terms of use, I typically just use the standard Apple App EULA, and included a link to that web page.  For Privacy Policy, Truste (a leading privacy provider) offers free customized privacy policies for Apps at http://www.truste.com/free-mobile-privacy-policy/  Answer a few questions about your app, and Truste will generate a web page you can use for your privacy policy.  Here is a screen shot of the settings page.


Code factoring (and re-factoring)
During the prototype phase the intent is quick and dirty code that confirms the apps functionality.  However, there is always improvements and refinements that should made.  In addition, when the same functionality is available from multiple points in the app, using common code improves your ability to troubleshoot your code.  Titanium supports RequireJS, which is a module loader that allows you to write common functions and objects that are re-usable.  In this app, there are two key common modules, core.js and functions.js.  Core.js is provided with the Chariti framework, and I created the functions.js for common app functions.

Device Testing
It is very important to test you app on an actual device, preferably as many as you can, including different versions.  This app will support iOS 6 and 7, and testing was performed on an iPhone 3, iPhone 5, and iPad 3.  Testing on a device provides the best way to judge the size and position of screen elements, as well as the usability of the app.  For device testing, I highly recommend using http://testflightapp.com which provides a service for uploading new app images and providing Over the Air installation during the development phase.  

Up Next
Now that the code is mostly complete (I am sure I will find some additional items as testing continues), it is time for the graphic assets.  Tune in next time for that topic!

As always ... comments are appreciated, as are +1's and Tweets!

Running Total Hours
Activities Completed
  • App Coding to "Beta" - 16 hours
Total Hours to date 28.5

Previous Part 5 - iPhone and iPad 
Next Part 7  - Graphic Assets

Tuesday, March 4, 2014

Journey to App - Part 5 - Addressing iPhone and iPad Form Factors

On the next step in our Journey to App, we will discuss addressing the different form factors for the iPhone and iPad.  In today's world of App development, your app needs to support both the iPhone and the iPad, and preferably, the user interface will leverage the strength of each platform and screen size.

Typically, the main difference between iPhone and iPad for productivity apps, has to do with how much information can be presented at once.  For our PDF app, we will use typical design patterns for both the iPhone and the iPad.  

For the iPhone, the UI is very hierarchical ... with each screen having a dedicated function, such as a list of files, or a preview of a file.  For the iPad, with the additional screen real estate, both the list of files, as well as the preview of a file can be shown on the screen at the same time.

For my development process, I like to tackle the different form factors, once the prototyping phase is complete.  I often find that there are additional functional problems to solve, and with the PDF app it was no different.

The key functionality that needed to be developed was cycling through documents on the preview.  For the iPhone, it is fine to preview a single file at a time, but for the iPad, I wanted to make it easy for the user to cycle through the files.  To accomplish this, I needed to use another Titanium Module.  Luckily, there was an open source one called Ti.Quicklook that had the functionality that we needed.  As a point, working with Appcelerator Titanium is great, because it has a very active development community, which makes it much easier to find examples and usable code to incorporate into your app.

In addition to new functionality, you will typically need to detect and provide conditional code to address the different form factors.

Here is an example of some code branching that detects and executes code only if the app is running on iPad.

function doTableviewClick(e) {
   APP.log("debug", "documents.doTableviewClick.e | " + JSON.stringify(e));
   var path = e.row.path;
   var index = e.row.index;
   APP.log("debug", "documents.doTableviewClick.path: " + path);
   APP.log("debug", "documents.doTableviewClick.index: " + index);

   if (APP.Device.isTablet) {
      SELECTED = index;
      APP.addChild("document_detail", {
         index : index
      });
   } else {
      var z = Ti.UI.iOS.createDocumentViewer({
         url : path
      });
      z.show();
   }
};

Lets take a look at how the app looks like on the different form factors now that we have incorporated in the iPad.

PDF Document Handling - iPhone
PDF Document Handling - iPad


















URL History and Browser - iPhone

URL History and Browser - iPad






















Up Next ...
With the prototyping complete, and updating the UI to address iPhone and iPads, the next step is our app development process is to start our formal code review, add error handling and address language localization.

Running Total Hours

Activities
  • Developing iPad / iPhone UI updates - 5 hours
Total Hours to date 12.5 hours

Previous Part 4 - Prototyping
Next Part 6 - Coding