About a month before RunRevLive 2014, the team at Canela Software was looking at which conference sessions to attend. We ventured over to the conference website to download the conference app, and were shocked to discover no such application existed! So, as any developer naturally would, we decided to create one ourselves.
Besides fulfilling our desire for a conference application, we also wanted to put LiveCode's mobile features to the test. We also figured it would make an ideal proof of concept for a real-world application based on our own LiveCloud database technology.
About a week into development, it occurred to us that we might actually be able to productize and release the event app to the community. By giving the guts away, we could accomplish the dual goals of (A) sharing what we learned about the mobile environment in LiveCode, and (B) give a non-trivial example of what a project using LiveCloud looks like.
You can download the EventApp source here: http://livecloud.io/live-events-source/
Before we got started, we needed to determine what the project should to look like. What features did we absolutely need the app to have? What features did we actually have time to implement? We made some sketches of what the user story might look like on the whiteboard, and created some UI templates that we thought we could reuse.
We also needed to model the database for the features we were going to include. Once we had the project plan and data model finalized, we divided the tasks among the development team.
Following is a quick overview of how we accomplished certain tasks while working on this project. If you're interested in a more in-depth code tour, you can view that on the LiveCloud website: http://www./livecloud.io/html/downloads/liveevents/CodeTour.txt The summary is broken down into the sections where we spent most of our time: the events schedule, the comments section, and image sharing.
First, let's take a look at the scheduling portion of the application.
The data model for the scheduling portion was fairly straightforward. We had one table that stored the details of each session, and a second table that was used to store a given user's saved sessions.
For simplicity, since the changes would be relatively infrequent, we created and updated the session information manually, rather than creating a tool to do so. Obviously, we weren't able to do this for the user favorites.
Here is the general flow of what the schedule creation looked like.
1. Sync the events table to the device, for offline caching:
cdb_SyncDatabase "Event"
2. Load all the records to an array using the synced data:
// we only need to look at session records, not other types of events
put cdb_BuildQuery("type","=","session") into tQueryA
put cdb_BasicLocalQuery(tQueryA,"structured","Event") into tEventsA
3. Arrange the data:
An array was used to store events based on start time. This way each section of the schedule can be identified from the unique start times. A second array was created for a list of headers for each section. Start time is stored in seconds for simplicity in creating a sorted list and as a comparison to highlight conflicts.
The event array has this format:
gEventListA[start time in seconds][event line][event detail fields]
For example:
gEventListA[1410283910][1]["title"] => "Well Behaved Behaviors"
gEventListA[1410283910][1]["speaker"] => "Scott Rossi"
gEventListA[1410283910][2]["title"] => "Streamlining Daily Operations"
gEventListA[1410283910][2]["speaker"] => "Skip Kimpel"
The header array also used seconds as the first key for sorting, but since the header only included a time display, the value of each key was the start time also. So:
gSectionA[start time in seconds] => the start time
4. Create the schedule display:
The schedule control uses two templates to display the complete scrolling list: a header group and an event group. With the header array keys sorted (gSectionA), a simple repeat loop is used to create a section group consisting of a header template and one or more event templates. Each template has a custom handler used to populate the template with the appropriate data. Everything is arranged top to bottom and put into a master group for scrolling.
5. Create a favorites database:
Each event template had a custom property for the record ID from the event table. A click on the favorites icon either added the record details to the favorites table along with the user or deleted the favorite record. Basic API calls were used to save and delete a favorites record:
cdb_SaveRecord
cdb_DeleteRecord
Now, let's take a quick peek at how we did the Comments section.
The most important thing we realized was that we needed to store the comments and the comments' linked images in two separate tables. This allowed us to handle them separately, which gave us the flexibility to *drastically* optimize performance for the comments section. Therefore, saving a comment with images is a two part process.
Creating a new comment.
• Comments with attached images:
Two images are created from the attachment: one a max display size, and the other a preview thumbnail. Both images were saved to the image table.
put cdb_CreateCloudRecord(tRecordA,"hyperblob") into tRecordID
Since the image data is not saved to the database directly, an ID is created for each image and stored in the record (HyperBlob ID, different from the record ID). These two ID's are used in the main comment database. If no attachment is added, no ID's are stored in the main comment database.
2. Saving the comment:
The HyperBlob IDs we get after saving the images (if applicable) and the comment text is saved to the main comment database.
Of course, if creating a comment is a two part process, then downloading and displaying comments would be the same. This is actually where we were able to achieve quite a bit of optimization.
Intuitively, it would take much more time to download the comments' images than it would take to download the comments themselves. They would also take up much, much less space. With that in mind, this is what we did:
1. Sync the comments (without images) to the device for offline caching:
cdb_SyncDatabase "Comments"
2. Load the comment records and create a sorted list.
3. Create the comment display:
Copy the appropriate UI template from the assets card, and populate it with the data from each comment.
4. Load the images:
Once the comment text is loaded and displayed, a run through the comments happens again, looking for image references. The process so far has used less than 100 milliseconds.
Starting with the most recent comment, if a comment has an attached image, download and display that comment's low-res thumbnail image. A wait is added between each download to permit the user to navigate during this process.
5. Displaying the full-res image version:
When a user touches a thumbnail, the larger version is downloaded. A longer touch on the larger image show a dialogue asking if the user would like to save the image to their device.
Hopefully this window into our development process and challenges has been interesting or helpful to you. We are releasing the code for this application to the community under the MIT license, so feel free to dig in and make it your own.
Please feel free to share your comments, questions, or thoughts at livecloud.io.