Hi,
it’s time for the third part in my series about Garmin ConnectIQ app development. Previously I have already installed the ConnectIQ SDK and the Eclipse plugin as described in the Readme file.
The planned structure of the app is as follows:
- A Monkey C app is built on top of the App class. The App class takes care of initializing the application, what happens when started and stopped as well as creating the first view for the application.
- The view classes extend the Ui.View class, handle the layout and the presentation of the GUI components.
- Delegates implement the operations to the model data and the required business logics.
The following code excerpt contains the App class that takes care of the initialisation of the app and getting the initial view.
using Toybox.Application as App; using Toybox.WatchUi as Ui; class TableHockeyMadnessApp extends App.AppBase { function initialize() { AppBase.initialize(); } // onStart() is called on application start up function onStart(state) { } // onStop() is called when your application is exiting function onStop(state) { } // Return the initial view of your application here function getInitialView() { return [ new TableHockeyMadnessView(), new TableHockeyMadnessDelegate() ]; } }
The main view mainly contains text and a couple of buttons for starting the game and adding each player’s goal score. On the image below you’ll see a work in progress. As I am not very familiar with the Connect IQ SDK yet, my original idea was to implement the buttons by defining screen coordinates, place text and coloured areas on those, and listen for the tap events on those areas.
Inside the view class I have defined an internal class for the screen components (labels and buttons). The following code excerpt demonstrates the initialization of the labels and the buttons. First I create an array for the components to be placed on the view, then I create the items one by one and add to the array. For instance in the case of textual elements I use instances of Ui.Text with the desired text to be shown, x and y coordinates on the display, and the render colour as input. A similar kind of an initialisation is done for the button elements.
// Update the view function onUpdate(dc) { var app = App.getApp(); var pl1Curr = app.getProperty(PL1_SCORE); var pl2Curr = app.getProperty(PL2_SCORE); var timerCurr = app.getProperty(TIMER_COUNT); var pl1ScoreCount = "0"; if (null != pl1Curr) { pl1ScoreCount = pl1Curr.toString(); } var pl2ScoreCount = "0"; if (null != pl2Curr) { pl2ScoreCount = pl2Curr.toString(); } var timerCount = "01:00"; if (null != timerCurr) { timerCount = timerCurr.toString(); } var list = buttons.getList(); var vMiddle = dc.getHeight() / 2; // Update the scores and the timer count var pl1Score = new Ui.Text({:text=>pl1ScoreCount, :locX=>Ui.LAYOUT_HALIGN_LEFT, :locY=>vMiddle + 20, :color=>Gfx.COLOR_WHITE, :font=>Gfx.FONT_LARGE}); list[4] = pl1Score; var pl2Score = new Ui.Text({:text=>pl2ScoreCount, :locX=>Ui.LAYOUT_HALIGN_RIGHT, :locY=>vMiddle + 20, :color=>Gfx.COLOR_WHITE, :font=>Gfx.FONT_LARGE}); list[5] = pl2Score; var timeTitle = new Ui.Text({:text=>timerCount, :locX=>Ui.LAYOUT_HALIGN_CENTER, :locY=>Ui.LAYOUT_VALIGN_TOP + 30, :color=>Gfx.COLOR_WHITE}); list[1] = timeTitle; Ui.requestUpdate(); View.onUpdate(dc); }
In addition to that further essential functionalities residing in the view class are the function onUpdate() that updates the required elements of the view (player’s scores and the time display).
The class TableHockeyMadnessDelegate essentially has a timer instance and keeps on track of the user events (the function onTap()) by updating the values of the variables that are displayed on the view. Moreover, a few utility methods have been included:
- timerCallback() for reacting to the timer changes and the timeout.
- secsToMinsSecsAndHours() takes care of converting seconds (e.g. provided in the configuration) to bigger time units.
- getFormattedTime(hours, minutes, seconds) takes time as numerical input of hours, minutes and seconds and returns a corresponding formatted string.
- shouldEndGame() checks whether the time is up and the user should be given an indication of the finished game.
My implementation seems to work on the simulator, but when I export an app and try in on a real device, the timer does not seem to run and the buttons remain unresponsive. I had to force the device to shutdown, and unfortunately I wasn’t able to find anything on the log files.
In other words I have to study the reason for this problem more thoroughly and make some refactoring… I think I have to get back to this theme pretty soon, because it is pretty frustrating to have a working app on the simulator, but which on the other hand does not work on the actual device…