I've made progress on this app over the past few weeks, despite only being able to work on it now and then. As usual, my progress in building the app is outpacing my blogging about its construction. So, this blog post is at least the first of two in an effort to catch up. Here I give a report of the design of the app as of about two weeks ago.
Here is a screenshot of the app while running:
One obvious thing I need to work on is showing the time elapsed in the format of minutes:seconds. Using the example of brushing my teeth for 2 minutes, these intervals alert me half-way through (to switch from lower to upper teeth), then a warning 50 seconds later that I only have 10 seconds left, followed by the 2 minute bell. Really, this last alert is not necessary because the toothbrush I use just turns off automatically at 2 minutes. If I wanted to switch between lower and upper every 30 seconds, then just one interval setting of 30 would be needed. In the example of giving myself alerts while making a 12-minute conference presentation - a typical time limit - I would likely add alerts at intervals of 6 minutes (half-way point), 4 minutes (the 10-minute mark), 1 minute (just one minute remaining), and 45 seconds (to give myself 15 seconds to thank everyone and get off the stage). Of course, that would require four intervals, not three, so I would need to add one more interval to the app. (Hint hint: That's a clue about what's coming up in next blog post.)
Telling the Time in LiveCode with the Seconds
LiveCode uses midnight, January 1, 1970 as the start of the eon. Date and time functions are computed from that date.
Doing Two (or More) Things at Once
The important thing to note is that while the timer is running, the app is constantly checking to see if the user presses any buttons. In contrast, many apps work by waiting until the user presses a button to perform a task. The app does the task, then waits for the user to press another button. If the task takes a long time to complete, the user has to wait until the task is completed before any other buttons can be pressed. Doing one thing at a time versus doing multiple things at the same time may sound like a subtle difference, but it requires a special programming technique to pull this off.
Here is the code for the app's engine called MainEventLoop, a procedure I wrote to run everything in the background while the user chooses timing intervals and clicks buttons to stop and stop the app's timer:
1: on MainEventLoop 2: if varRunMainLoop is true then 3: lock screen 4: put the seconds into varSecondsEnd 5: LloydStopWatch 6: unlock screen 7: end if 8: put the pendingMessages into tMessages 9: repeat for each line aLine in tMessages 10: if item 3 of aLine is "mainEventLoop" then cancel item 1 of aLine 11: end repeat 12: send "mainEventLoop" to me in 50 milliseconds 13: end MainEventLoop 14: 15: on LloydStopWatch The magical code goes here 16: end LloydStopWatch
A procedure called MainEventLoop just runs and runs by looping forever while the app is running. This works by having it "call itself" in line 12 in a very short amount of time (i.e. 50 milliseconds). I know, that's a very weird idea. It's usually very hard for new programmers to grasp. I know it was for me. In that short amount of time, it completes any assigned task while "watching" to see if the user does something, such as clicking a button. There is nothing special about 50 ms. It could be called in one second, but 50 ms is plenty of time for the app to do its work.
Another procedure, LloydStopWatch, has all of the code that actually computes how many seconds have transpired since starting the timer. This code also keeps track of the intervals and knows when play a chime at the end of each interval. Note that line 5 is where the LloydStopWatch procedure is triggered, but only if the variable varRunMainLoop is true. This variable controls whether the timer is active. If the user clicks the Start button it becomes true. If the user clicks the Stop button, it switches to false.
So, how does one get MainEventLoop to start running. The answer is in the code for the button "Start:"
1: on mouseup 2: put 0 into varTimeCurrentLoop 3: put 0 into varIntervalTotal 4: put 1 into varIntervalTurn 5: put false into varRestartInterval 6: put empty into field "notes" 7: put empty into field "Interval Totals" 8: put empty into varTimeLog 9: put field "Iminutes1" into varIminutes1 10: put field "Iseconds1" into varIseconds1 11: put field "Iminutes2" into varIminutes2 12: put field "Iseconds2" into varIseconds2 13: put field "Iminutes3" into varIminutes3 14: put field "Iseconds3" into varIseconds3 15: put true into varRunMainLoop 16: put the seconds into varSecondsBegin 17: put varSecondsBegin into varSecondsBeginInterval 18: MainEventLoop 19: end mouseup
Lines 2-18 initiate all of the main fields and variables, essentially getting them ready for the start of a new timing session. Line 15 sets the variable varRunMainLoop to true and line 18 initiates the MainEventLoop procedure.
Lines 9-14 takes whatever interval values the user had entered and passes them on to unique variables for each for use within the LloydStopWatch procedure.
Line 16 essentially checks the current time and becomes the moment in time from which the time elapsed is figured. This value is held by the variable varSecondsBegin. Line 4 in the MainEventLoop procedure continually checks the current time, puts it in a variable named varSecondsEnd, then calls the LloydStopWatch procedure. The time elapsed in seconds is simply the difference between these two values. This simple subtraction problem is happening every 50 ms.
Finally, the timer stops when the user presses the "Stop" button - here is the code for the Stop button:
1: on mouseup 2: put false into varRunMainLoop 3: end mouseup
By changing the value of varRunMainLoop to false, it stops the loop within MainEventLoop that had been triggering the LloydStopWatch procedure.
Short List of Things to Do
Actually, the list is quite long, but here are some of the obvious revisions and updates that are needed:
- Add a fourth timer interval
- Change the elapsed time format
- Allow the user to pause the timer
- Add a choice of alert sounds
- Add a mobile interface design, including spinner wheels to select time intervals and a vibrate option for alerts