├── resources ├── layouts │ └── layout.xml ├── strings │ └── strings.xml ├── drawables │ ├── mute-2-12.png │ ├── mute-2-13.png │ ├── alarm-clock-12.png │ ├── alarm-clock-13.png │ ├── alarm-clock-14.png │ ├── alarm-clock-15.png │ ├── alarm-clock-16.png │ ├── bluetooth-2-12.png │ ├── bluetooth-2-13.png │ ├── bluetooth-2-14.png │ ├── bluetooth-2-15.png │ ├── bluetooth-2-16.png │ ├── launcher_icon.png │ ├── speech-bubble-12.png │ ├── speech-bubble-13.png │ ├── speech-bubble-14.png │ ├── speech-bubble-15.png │ ├── speech-bubble-16.png │ └── drawables.xml └── resources.xml ├── bin ├── SnapshotWatch.prg ├── SnapshotWatch-settings.json └── SnapshotWatch.prg.debug.xml ├── .project ├── source ├── SnapshotWatchApp.mc ├── SunCalc.mc └── SnapshotWatchView.mc ├── manifest.xml └── README.md /resources/layouts/layout.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bin/SnapshotWatch.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/bin/SnapshotWatch.prg -------------------------------------------------------------------------------- /resources/strings/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SnapshotWatch 3 | 4 | -------------------------------------------------------------------------------- /resources/drawables/mute-2-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/mute-2-12.png -------------------------------------------------------------------------------- /resources/drawables/mute-2-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/mute-2-13.png -------------------------------------------------------------------------------- /resources/drawables/alarm-clock-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/alarm-clock-12.png -------------------------------------------------------------------------------- /resources/drawables/alarm-clock-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/alarm-clock-13.png -------------------------------------------------------------------------------- /resources/drawables/alarm-clock-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/alarm-clock-14.png -------------------------------------------------------------------------------- /resources/drawables/alarm-clock-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/alarm-clock-15.png -------------------------------------------------------------------------------- /resources/drawables/alarm-clock-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/alarm-clock-16.png -------------------------------------------------------------------------------- /resources/drawables/bluetooth-2-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/bluetooth-2-12.png -------------------------------------------------------------------------------- /resources/drawables/bluetooth-2-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/bluetooth-2-13.png -------------------------------------------------------------------------------- /resources/drawables/bluetooth-2-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/bluetooth-2-14.png -------------------------------------------------------------------------------- /resources/drawables/bluetooth-2-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/bluetooth-2-15.png -------------------------------------------------------------------------------- /resources/drawables/bluetooth-2-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/bluetooth-2-16.png -------------------------------------------------------------------------------- /resources/drawables/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/launcher_icon.png -------------------------------------------------------------------------------- /resources/drawables/speech-bubble-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/speech-bubble-12.png -------------------------------------------------------------------------------- /resources/drawables/speech-bubble-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/speech-bubble-13.png -------------------------------------------------------------------------------- /resources/drawables/speech-bubble-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/speech-bubble-14.png -------------------------------------------------------------------------------- /resources/drawables/speech-bubble-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/speech-bubble-15.png -------------------------------------------------------------------------------- /resources/drawables/speech-bubble-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darrencroton/SnapshotWatch/HEAD/resources/drawables/speech-bubble-16.png -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | SnapshotWatch 4 | 5 | 6 | 7 | 8 | 9 | connectiq.builder 10 | 11 | 12 | 13 | 14 | 15 | connectiq.projectNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /resources/drawables/drawables.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/SnapshotWatchApp.mc: -------------------------------------------------------------------------------- 1 | using Toybox.Application as App; 2 | 3 | class SnapshotWatchApp extends App.AppBase { 4 | 5 | function initialize() { 6 | AppBase.initialize(); 7 | } 8 | 9 | // onStart() is called on application start up 10 | function onStart(state) { 11 | } 12 | 13 | // onStop() is called when your application is exiting 14 | function onStop(state) { 15 | } 16 | 17 | // Return the initial view of your application here 18 | function getInitialView() { 19 | return [ new SnapshotWatchView() ]; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Snapshot Watch 2 | A clean, simple, and elegant analogue watch face for the Forerunner 735XT that plots a heart rate graph of your last 4 hours in the background. 3 | 4 | In addition, most of your daily data is shown in an unobtrusive way: day and date, current/minimum/maximum heart rate, steps and step goal, sunrise/sunset, and icons for notification count/bluetooth/alarms/do not disturb. 5 | 6 | The heart rate graph and information can be turned off in the settings, and a second digital time (with or without offset) turned on. 7 | 8 | Snapshot Watch can be downloaded to your device here: https://apps.garmin.com/en-US/apps/20b5e4c9-382c-429d-91fa-199869c4777b. 9 | 10 | A special thanks to haraldh/SunCalc, from whom i borrowed code to calculate sunrise and sunset times: https://github.com/haraldh/SunCalc. 11 | -------------------------------------------------------------------------------- /source/SunCalc.mc: -------------------------------------------------------------------------------- 1 | using Toybox.Math as Math; 2 | using Toybox.Time as Time; 3 | 4 | enum { 5 | NIGHT_END, 6 | NAUTICAL_DAWN, 7 | DAWN, 8 | BLUE_HOUR_AM, 9 | SUNRISE, 10 | SUNRISE_END, 11 | GOLDEN_HOUR_AM, 12 | NOON, 13 | GOLDEN_HOUR_PM, 14 | SUNSET_START, 15 | SUNSET, 16 | BLUE_HOUR_PM, 17 | DUSK, 18 | NAUTICAL_DUSK, 19 | NIGHT, 20 | NUM_RESULTS 21 | } 22 | 23 | class SunCalc { 24 | 25 | hidden const PI = Math.PI, 26 | RAD = Math.PI / 180.0, 27 | PI2 = Math.PI * 2.0, 28 | DAYS = Time.Gregorian.SECONDS_PER_DAY, 29 | J1970 = 2440588, 30 | J2000 = 2451545, 31 | J0 = 0.0009; 32 | 33 | hidden const TIMES = [ 34 | -18 * RAD, 35 | -12 * RAD, 36 | -6 * RAD, 37 | -4 * RAD, 38 | -0.833 * RAD, 39 | -0.3 * RAD, 40 | 6 * RAD, 41 | null, 42 | 6 * RAD, 43 | -0.3 * RAD, 44 | -0.833 * RAD, 45 | -4 * RAD, 46 | -6 * RAD, 47 | -12 * RAD, 48 | -18 * RAD 49 | ]; 50 | 51 | var lastD, lastLng; 52 | var n, ds, M, sinM, C, L, sin2L, dec, Jnoon; 53 | 54 | function initialize() { 55 | lastD = null; 56 | lastLng = null; 57 | } 58 | 59 | function fromJulian(j) { 60 | return new Time.Moment((j + 0.5 - J1970) * DAYS); 61 | } 62 | 63 | function round(a) { 64 | if (a > 0) { 65 | return (a + 0.5).toNumber().toFloat(); 66 | } else { 67 | return (a - 0.5).toNumber().toFloat(); 68 | } 69 | } 70 | 71 | // lat and lng in radians 72 | function calculate(moment, lat, lng, what) { 73 | var d = moment.value().toDouble() / DAYS - 0.5 + J1970 - J2000; 74 | if (lastD != d || lastLng != lng) { 75 | n = round(d - J0 + lng / PI2); 76 | // ds = J0 - lng / PI2 + n; 77 | ds = J0 - lng / PI2 + n - 1.1574e-5 * 68; 78 | M = 6.240059967 + 0.0172019715 * ds; 79 | sinM = Math.sin(M); 80 | C = (1.9148 * sinM + 0.02 * Math.sin(2 * M) + 0.0003 * Math.sin(3 * M)) * RAD; 81 | L = M + C + 1.796593063 + PI; 82 | sin2L = Math.sin(2 * L); 83 | dec = Math.asin( 0.397783703 * Math.sin(L) ); 84 | Jnoon = J2000 + ds + 0.0053 * sinM - 0.0069 * sin2L; 85 | lastD = d; 86 | lastLng = lng; 87 | } 88 | 89 | if (what == NOON) { 90 | return fromJulian(Jnoon); 91 | } 92 | 93 | var x = (Math.sin(TIMES[what]) - Math.sin(lat) * Math.sin(dec)) / (Math.cos(lat) * Math.cos(dec)); 94 | 95 | if (x > 1.0 || x < -1.0) { 96 | return null; 97 | } 98 | 99 | var ds = J0 + (Math.acos(x) - lng) / PI2 + n - 1.1574e-5 * 68; 100 | 101 | var Jset = J2000 + ds + 0.0053 * sinM - 0.0069 * sin2L; 102 | if (what > NOON) { 103 | return fromJulian(Jset); 104 | } 105 | 106 | var Jrise = Jnoon - (Jset - Jnoon); 107 | 108 | return fromJulian(Jrise); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /bin/SnapshotWatch-settings.json: -------------------------------------------------------------------------------- 1 | {"settings":[{"key":"code","valueType":"string","defaultValue":"get code at app store page","configTitle":"CodeLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"alphaNumeric","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"showHeartRate","valueType":"boolean","defaultValue":true,"configTitle":"ShowHeartRateLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"boolean","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"graphLength","valueType":"number","defaultValue":240,"configTitle":"GraphLengthLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"numeric","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"graphColour","valueType":"number","defaultValue":0,"configTitle":"GraphColourLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"list","configReadonly":false,"configRequired":true,"configOptions":[{"display":"DK_GRAY","value":0},{"display":"RED","value":1},{"display":"DK_RED","value":2},{"display":"ORANGE","value":3},{"display":"YELLOW","value":4},{"display":"GREEN","value":5},{"display":"DK_GREEN","value":6},{"display":"BLUE","value":7},{"display":"DK_BLUE","value":8},{"display":"PURPLE","value":9},{"display":"PINK","value":10}],"configMin":null,"configMax":null,"configMaxLength":null},{"key":"useZonesColour","valueType":"boolean","defaultValue":true,"configTitle":"UseZonesColourLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"boolean","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"showMoveBar","valueType":"boolean","defaultValue":false,"configTitle":"ShowMoveBarLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"boolean","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"showSteps","valueType":"boolean","defaultValue":false,"configTitle":"ShowStepsLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"boolean","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"showRiseSet","valueType":"boolean","defaultValue":false,"configTitle":"ShowRiseSetLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"boolean","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"showSecondTime","valueType":"boolean","defaultValue":false,"configTitle":"ShowSecondTimeLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"boolean","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null},{"key":"secondTimeOffset","valueType":"number","defaultValue":0,"configTitle":"SecondTimeOffsetLabel","configPrompt":null,"configHelpUrl":null,"configError":null,"configType":"numeric","configReadonly":false,"configRequired":false,"configOptions":null,"configMin":null,"configMax":null,"configMaxLength":null}],"languages":{"valyrian":{"UseZonesColourLabel":"Additionally colour code graph by profile heart rate zones","ShowRiseSetLabel":"[PRO] Show sunrise/sunset","DK_GRAY":"Dark Gray","DK_GREEN":"Dark Green","BLUE":"Blue","SecondTimeOffsetLabel":"[PRO] Second (digital) time hour offset (integer, +-24)","PURPLE":"Purple","GREEN":"Green","ShowMoveBarLabel":"Colour graph red when move bar alert is on (or orange if red set above)","DK_RED":"Dark Red","DK_BLUE":"Dark Blue","AppName":"SnapshotWatch","RED":"Red","PINK":"Pink","CodeLabel":"Activation code for PRO features","ShowHeartRateLabel":"Show heart rate, graph, and min/max values","GraphLengthLabel":"Number of past minutes to show in heart rate graph (minimum 15, maximum 240)","GraphColourLabel":"Heart rate graph colour","ShowSecondTimeLabel":"[PRO] Show second (digital) time","YELLOW":"Yellow","ORANGE":"Orange","ShowStepsLabel":"[PRO] Show steps/step goal"}}} -------------------------------------------------------------------------------- /resources/resources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | get code at app store page 5 | true 6 | 240 7 | 0 8 | true 9 | false 10 | false 11 | false 12 | false 13 | 0 14 | 15 | 16 | 17 | Activation code for PRO features 18 | Show heart rate, graph, and min/max values 19 | Number of past minutes to show in heart rate graph (minimum 15, maximum 240) 20 | Heart rate graph colour 21 | Dark Gray 22 | Red 23 | Dark Red 24 | Orange 25 | Yellow 26 | Green 27 | Dark Green 28 | Blue 29 | Dark Blue 30 | Purple 31 | Pink 32 | Additionally colour code graph by profile heart rate zones 33 | Colour graph red when move bar alert is on (or orange if red set above) 34 | [PRO] Show steps/step goal 35 | [PRO] Show sunrise/sunset 36 | [PRO] Show second (digital) time 37 | [PRO] Second (digital) time hour offset (integer, +-24) 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | @Strings.DK_GRAY 53 | @Strings.RED 54 | @Strings.DK_RED 55 | @Strings.ORANGE 56 | @Strings.YELLOW 57 | @Strings.GREEN 58 | @Strings.DK_GREEN 59 | @Strings.BLUE 60 | @Strings.DK_BLUE 61 | @Strings.PURPLE 62 | @Strings.PINK 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /source/SnapshotWatchView.mc: -------------------------------------------------------------------------------- 1 | using Toybox.Graphics as Gfx; 2 | using Toybox.System as Sys; 3 | using Toybox.Lang as Lang; 4 | using Toybox.Math as Math; 5 | using Toybox.Time as Time; 6 | using Toybox.Time.Gregorian as Calendar; 7 | using Toybox.WatchUi as Ui; 8 | using Toybox.Application as App; 9 | using Toybox.ActivityMonitor as ActMon; 10 | using Toybox.SensorHistory as Sensor; 11 | using Toybox.Activity as Activity; 12 | using Toybox.UserProfile as User; 13 | 14 | enum 15 | { 16 | LAT, 17 | LON 18 | } 19 | 20 | 21 | class SnapshotWatchView extends Ui.WatchFace { 22 | 23 | var usePreferences = true; 24 | var showHeartRate = true; 25 | var showSteps = false; 26 | var showRiseSet = false; 27 | var showSecondTime = false; 28 | var secondTimeOffset = 0; 29 | 30 | var graphLength = 240; 31 | var arrayColours = new [11]; 32 | var graphColour = 0; 33 | var useZonesColour = true; 34 | var heartRateZones; 35 | var showMoveBar = false; 36 | 37 | var background_color = Gfx.COLOR_BLACK; 38 | // var background_color = Gfx.COLOR_DK_GRAY; 39 | 40 | var showSeconds = true; 41 | var width_screen, height_screen; 42 | var hashMarksArray = new [60]; 43 | 44 | var heartNow; 45 | var heartMin = 1000; 46 | var heartMax = 0; 47 | 48 | var proFeatures; 49 | 50 | 51 | //! Load your resources here 52 | function onLayout(dc) { 53 | 54 | //get screen dimensions 55 | width_screen = dc.getWidth(); 56 | height_screen = dc.getHeight(); 57 | 58 | //colours and zones 59 | arrayColours = [Gfx.COLOR_DK_GRAY, Gfx.COLOR_RED, Gfx.COLOR_DK_RED, Gfx.COLOR_ORANGE, Gfx.COLOR_YELLOW, Gfx.COLOR_GREEN, Gfx.COLOR_DK_GREEN, Gfx.COLOR_BLUE, Gfx.COLOR_DK_BLUE, Gfx.COLOR_PURPLE, Gfx.COLOR_PINK]; 60 | heartRateZones = User.getHeartRateZones(User.getCurrentSport()); 61 | // heartRateZones = [98, 127, 146, 166, 185, 195]; 62 | 63 | //get hash marks position 64 | for(var i = 0; i < 60; i+=1) 65 | { 66 | hashMarksArray[i] = new [2]; 67 | hashMarksArray[i][0] = (i / 60.0) * Math.PI * 2; 68 | 69 | if(i != 0 && i != 15 && i != 30 && i != 45) 70 | { hashMarksArray[i][1] = -85; } 71 | else 72 | { hashMarksArray[i][1] = -67; } 73 | } 74 | 75 | setLayout(Rez.Layouts.WatchFace(dc)); 76 | } 77 | 78 | 79 | //! Restore the state of the app and prepare the view to be shown 80 | function onShow() { 81 | } 82 | 83 | //! Update the view 84 | function onUpdate(dc) { 85 | 86 | var code = "0"; 87 | 88 | if (usePreferences) 89 | { 90 | code = Application.getApp().getProperty("code"); 91 | showHeartRate = Application.getApp().getProperty("showHeartRate"); 92 | graphLength = Application.getApp().getProperty("graphLength"); 93 | graphColour = Application.getApp().getProperty("graphColour"); 94 | useZonesColour = Application.getApp().getProperty("useZonesColour"); 95 | showMoveBar = Application.getApp().getProperty("showMoveBar"); 96 | showSteps = Application.getApp().getProperty("showSteps"); 97 | showRiseSet = Application.getApp().getProperty("showRiseSet"); 98 | showSecondTime = Application.getApp().getProperty("showSecondTime"); 99 | secondTimeOffset = Application.getApp().getProperty("secondTimeOffset"); 100 | } 101 | 102 | authenticate(code); 103 | 104 | if (!proFeatures) 105 | { 106 | showSteps = false; 107 | showRiseSet = false; 108 | showSecondTime = false; 109 | } 110 | 111 | if (showSecondTime) 112 | { 113 | if (secondTimeOffset != null && secondTimeOffset <= 24 && secondTimeOffset >= -24) 114 | { 115 | secondTimeOffset = secondTimeOffset.toNumber(); 116 | } 117 | else 118 | { 119 | showSecondTime = false; 120 | secondTimeOffset = 0; 121 | } 122 | } 123 | 124 | // Clear screen 125 | dc.setColor(background_color, Gfx.COLOR_WHITE); 126 | dc.fillRectangle(0,0, width_screen, height_screen); 127 | 128 | heartNow = 0; 129 | 130 | // Plot heart rate graph 131 | plotHRgraph(dc); 132 | 133 | // Draw hash marks 134 | drawHashMarks(dc); 135 | 136 | // Draw analogue clock hands 137 | drawHands(dc, Sys.getClockTime().hour, Sys.getClockTime().min, Sys.getClockTime().sec); 138 | 139 | // Set text colour for the remaining information 140 | dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_TRANSPARENT); 141 | 142 | // Show cur/min/max HR values (recorded when plotting graph, above) 143 | if (showHeartRate) 144 | { 145 | if (heartNow == 0) 146 | { dc.drawText(width_screen/2, height_screen/2 + 20, Gfx.FONT_SMALL, "-- bpm", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); } 147 | else 148 | { dc.drawText(width_screen/2, height_screen/2 + 20, Gfx.FONT_SMALL, Lang.format("$1$ bpm", [heartNow]), Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); } 149 | 150 | var heartMinMaxString; 151 | if (heartMin == 0 || heartMax == 0) 152 | { heartMinMaxString = "-- / -- bpm"; } 153 | else 154 | { heartMinMaxString = Lang.format("$1$ / $2$ bpm", [heartMin, heartMax]); } 155 | 156 | dc.drawText(width_screen/2, height_screen - 19, Gfx.FONT_SMALL, heartMinMaxString, Graphics.TEXT_JUSTIFY_CENTER); 157 | } 158 | 159 | // Show date 160 | drawDate(dc); 161 | 162 | // Show second (digital) time 163 | drawDigitalTime(dc, Sys.getClockTime()); 164 | 165 | // Show bluetooth icon 166 | if (Sys.getDeviceSettings().phoneConnected) 167 | { dc.drawBitmap(39, 6, Ui.loadResource(Rez.Drawables.BluetoothIcon)); } 168 | 169 | // Show alarm icon 170 | if (Sys.getDeviceSettings().alarmCount > 0) 171 | { dc.drawBitmap(25, 23, Ui.loadResource(Rez.Drawables.AlarmIcon)); } 172 | 173 | // Show do not disturb icon 174 | if (Sys.getDeviceSettings().doNotDisturb) 175 | { dc.drawBitmap(10, 49, Ui.loadResource(Rez.Drawables.MuteIcon)); } 176 | 177 | // Show notification count icon 178 | if (Sys.getDeviceSettings().notificationCount > 0) 179 | { 180 | var offset = 0; 181 | if (Sys.getDeviceSettings().notificationCount >= 10) { offset = 6; } 182 | 183 | dc.drawText(width_screen/2+16+offset, 7, Gfx.FONT_SMALL, Sys.getDeviceSettings().notificationCount, Graphics.TEXT_JUSTIFY_RIGHT|Graphics.TEXT_JUSTIFY_VCENTER); 184 | dc.drawBitmap(width_screen/2+18+offset, 2, Ui.loadResource(Rez.Drawables.NotificationIcon)); 185 | } 186 | 187 | // Show battery percent 188 | var battery = Sys.getSystemStats().battery; 189 | var offset = 0; 190 | if (battery == 100) 191 | { offset = 6; } 192 | dc.drawText(width_screen/2-33-offset, 7, Gfx.FONT_SMALL, Lang.format("$1$%", [battery.format("%2d")]), Graphics.TEXT_JUSTIFY_LEFT|Graphics.TEXT_JUSTIFY_VCENTER); 193 | 194 | if (showSteps) 195 | { 196 | // Show steps 197 | dc.drawText(width_screen-4, height_screen/2 - 14, Gfx.FONT_SMALL, ActMon.getInfo().steps, Graphics.TEXT_JUSTIFY_RIGHT|Graphics.TEXT_JUSTIFY_VCENTER); 198 | dc.drawText(width_screen-4, height_screen/2 + 11, Gfx.FONT_SMALL, ActMon.getInfo().stepGoal, Graphics.TEXT_JUSTIFY_RIGHT|Graphics.TEXT_JUSTIFY_VCENTER); 199 | } 200 | 201 | if (showRiseSet) 202 | { 203 | // Show sunrise and sunset 204 | drawSunriseSunset(dc); 205 | } 206 | 207 | } 208 | 209 | 210 | //! The user has just looked at their watch. Timers and animations may be started here. 211 | function onExitSleep() { 212 | showSeconds = true; 213 | } 214 | 215 | 216 | //! Terminate any active timers and prepare for slow updates. 217 | function onEnterSleep() { 218 | showSeconds = false; 219 | requestUpdate(); 220 | } 221 | 222 | 223 | function plotHRgraph(dc) { 224 | 225 | var curHeartMin = 0; 226 | var curHeartMax = 0; 227 | 228 | var sample = Sensor.getHeartRateHistory( {:order=>Sensor.ORDER_NEWEST_FIRST} ); 229 | if (sample != null) 230 | { 231 | var heart = sample.next(); 232 | if (heart.data != null) 233 | { heartNow = heart.data; } 234 | 235 | if (showHeartRate) 236 | { 237 | curHeartMin = heartMin; 238 | curHeartMax = heartMax; 239 | heartMin = 1000; 240 | heartMax = 0; 241 | 242 | var maxSecs = graphLength * 60; 243 | if (maxSecs < 900) 244 | { maxSecs = 900; } // 900sec = 15min 245 | else if (maxSecs > 14355) 246 | { maxSecs = 14355; } // 14400sec = 4hrs 247 | 248 | var totHeight = 44; 249 | var totWidth = 165; 250 | var binPixels = 1; 251 | 252 | var totBins = Math.ceil(totWidth / binPixels).toNumber(); 253 | var binWidthSecs = Math.floor(binPixels * maxSecs / totWidth).toNumber(); 254 | 255 | var heartSecs; 256 | var heartValue = 0; 257 | var secsBin = 0; 258 | var lastHeartSecs = sample.getNewestSampleTime().value(); 259 | var heartBinMax; 260 | var heartBinMin; 261 | 262 | var finished = false; 263 | 264 | for (var i = 0; i < totBins; ++i) { 265 | 266 | heartBinMax = 0; 267 | heartBinMin = 0; 268 | 269 | if (!finished) 270 | { 271 | //deal with carryover values 272 | if (secsBin > 0 && heartValue != null) 273 | { 274 | heartBinMax = heartValue; 275 | heartBinMin = heartValue; 276 | } 277 | 278 | //deal with new values in this bin 279 | while (!finished && secsBin < binWidthSecs) 280 | { 281 | heart = sample.next(); 282 | if (heart != null) 283 | { 284 | heartValue = heart.data; 285 | if (heartValue != null) 286 | { 287 | if (heartBinMax == 0) 288 | { 289 | heartBinMax = heartValue; 290 | heartBinMin = heartValue; 291 | } 292 | else 293 | { 294 | if (heartValue > heartBinMax) 295 | { heartBinMax = heartValue; } 296 | 297 | if (heartValue < heartBinMin) 298 | { heartBinMin = heartValue; } 299 | } 300 | } 301 | 302 | // keep track of time in this bin 303 | heartSecs = lastHeartSecs - heart.when.value(); 304 | lastHeartSecs = heart.when.value(); 305 | secsBin += heartSecs; 306 | 307 | // Sys.println(i + ": " + heartValue + " " + heartSecs + " " + secsBin + " " + heartBinMin + " " + heartBinMax); 308 | } 309 | else 310 | { 311 | finished = true; 312 | } 313 | 314 | } // while secsBin < binWidthSecs 315 | 316 | if (secsBin >= binWidthSecs) 317 | { secsBin -= binWidthSecs; } 318 | 319 | // only plot bar if we have valid values 320 | if (heartBinMax > 0 && heartBinMax >= heartBinMin) 321 | { 322 | if (curHeartMax > 0 && curHeartMax > curHeartMin) 323 | { 324 | var heartBinMid = (heartBinMax+heartBinMin)/2; 325 | var height = (heartBinMid-curHeartMin*0.9) / (curHeartMax-curHeartMin*0.9) * totHeight; 326 | var xVal = (width_screen-totWidth)/2 + totWidth - i*binPixels -2; 327 | var yVal = height_screen/2+28 + totHeight - height; 328 | 329 | if (showMoveBar && ActMon.getInfo().moveBarLevel > 0) 330 | { 331 | if (graphColour == 1) 332 | { dc.setColor(Gfx.COLOR_ORANGE, Gfx.COLOR_TRANSPARENT); } 333 | else 334 | { dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_TRANSPARENT); } 335 | } else 336 | { 337 | dc.setColor(arrayColours[getHRColour(heartBinMid)], Gfx.COLOR_TRANSPARENT); 338 | } 339 | 340 | dc.fillRectangle(xVal, yVal, binPixels, height); 341 | } 342 | 343 | if (heartBinMin < heartMin) 344 | { heartMin = heartBinMin; } 345 | if (heartBinMax > heartMax) 346 | { heartMax = heartBinMax; } 347 | 348 | // Sys.println(i + ": " + binWidthSecs + " " + secsBin + " " + heartBinMin + " " + heartBinMax); 349 | } 350 | 351 | } // if !finished 352 | 353 | } // loop over all bins 354 | 355 | } // if sample != null 356 | 357 | } 358 | } 359 | 360 | 361 | function getHRColour(heartrate) 362 | { 363 | if (!useZonesColour || heartrate == null || heartrate < heartRateZones[1]) 364 | { return graphColour; } 365 | // else if (heartrate >= heartRateZones[0] && heartrate < heartRateZones[1]) 366 | // { return 0; } 367 | else if (heartrate >= heartRateZones[1] && heartrate < heartRateZones[2]) 368 | { return 7; } 369 | else if (heartrate >= heartRateZones[2] && heartrate < heartRateZones[3]) 370 | { return 5; } 371 | else if (heartrate >= heartRateZones[3] && heartrate < heartRateZones[4]) 372 | { return 3; } 373 | else 374 | { return 2; } 375 | } 376 | 377 | 378 | //! Draw the watch hand 379 | function drawHand(dc, angle, whichHand, width, handColour) 380 | { 381 | dc.setColor(handColour, Gfx.COLOR_TRANSPARENT); 382 | 383 | var length, r1, r2, r3, r4, deflect1, deflect2; 384 | 385 | var centerX = width_screen/2; 386 | var centerY = height_screen/2; 387 | 388 | if (whichHand == 0) //hour hand 389 | { 390 | length = 0.6*centerX; 391 | r1 = 0.0*length; 392 | r2 = 0.39*length; 393 | r3 = 0.49*length; 394 | r4 = 1.1*length; 395 | deflect1 = 0.10*width; 396 | deflect2 = 0.08*width; 397 | } 398 | else //minute hand 399 | { 400 | length = 1.0*centerX; 401 | r1 = 0.0*length; 402 | r2 = 0.37*length; 403 | r3 = 0.47*length; 404 | r4 = 1.2*length; 405 | deflect1 = 0.10*width; 406 | deflect2 = 0.08*width; 407 | } 408 | 409 | var coords = [ 410 | [centerX + r1 * Math.sin(angle) , centerY - r1 * Math.cos(angle)], 411 | [centerX + r2 * Math.sin(angle+deflect1) , centerY - r2 * Math.cos(angle+deflect1)], 412 | [centerX + r3 * Math.sin(angle+deflect2) , centerY - r3 * Math.cos(angle+deflect2)], 413 | [centerX + r4 * Math.sin(angle) , centerY - r4 * Math.cos(angle)], 414 | [centerX + r3 * Math.sin(angle-deflect2) , centerY - r3 * Math.cos(angle-deflect2)], 415 | [centerX + r2 * Math.sin(angle-deflect1) , centerY - r2 * Math.cos(angle-deflect1)], 416 | [centerX + r1 * Math.sin(angle) , centerY - r1 * Math.cos(angle)] 417 | ]; 418 | 419 | dc.fillPolygon(coords); 420 | 421 | } 422 | 423 | 424 | function drawHands(dc, clock_hour, clock_min, clock_sec) 425 | { 426 | var hour, min, sec; 427 | 428 | // Draw the hour hand - convert to minutes then compute angle 429 | hour = ( ( ( clock_hour % 12 ) * 60 ) + clock_min ); // hour = 2*60.0; 430 | hour = hour / (12 * 60.0) * Math.PI * 2; 431 | drawHand(dc, hour, 0, 2.0, Gfx.COLOR_DK_BLUE); 432 | drawHand(dc, hour, 0, 1.6, Gfx.COLOR_LT_GRAY); 433 | 434 | // Draw the minute hand 435 | min = ( clock_min / 60.0); // min = 40/60.0; 436 | min = min * Math.PI * 2; 437 | drawHand(dc, min, 1, 1.2, Gfx.COLOR_DK_BLUE); 438 | drawHand(dc, min, 1, 1.0, Gfx.COLOR_LT_GRAY); 439 | 440 | // Draw the seconds hand (use hash graphic here) 441 | if(showSeconds) 442 | { 443 | sec = ( clock_sec / 60.0) * Math.PI * 2; 444 | drawHash(dc, sec, width_screen/2, 4, 25, Gfx.COLOR_DK_BLUE); 445 | drawHash(dc, sec, width_screen/2, 2, 25, Gfx.COLOR_LT_GRAY); 446 | } 447 | 448 | // Draw the inner circle 449 | dc.setColor(Gfx.COLOR_DK_GRAY, background_color); 450 | dc.fillCircle(width_screen/2, height_screen/2, 6); 451 | dc.setColor(background_color,background_color); 452 | dc.drawCircle(width_screen/2, height_screen/2, 6); 453 | dc.fillCircle(width_screen/2, height_screen/2, 2); 454 | } 455 | 456 | 457 | function drawHash(dc, angle, length, width, overheadLine, handColour) 458 | { 459 | dc.setColor(handColour, Gfx.COLOR_TRANSPARENT); 460 | 461 | var centerX = width_screen/2; 462 | var centerY = height_screen/2; 463 | 464 | var result = new [4]; 465 | var cos = Math.cos(angle); 466 | var sin = Math.sin(angle); 467 | 468 | var coords = [ 469 | [-(width/2), 0 + overheadLine], 470 | [-(width/2), -length], 471 | [width/2, -length], 472 | [width/2, 0 + overheadLine] 473 | ]; 474 | 475 | for (var i = 0; i < 4; i += 1) 476 | { 477 | var x = (coords[i][0] * cos) - (coords[i][1] * sin); 478 | var y = (coords[i][0] * sin) + (coords[i][1] * cos); 479 | result[i] = [ centerX + x, centerY + y]; 480 | } 481 | 482 | dc.fillPolygon(result); 483 | 484 | } 485 | 486 | 487 | //! Draw the hash mark symbols 488 | function drawHashMarks(dc) 489 | { 490 | drawHash(dc, hashMarksArray[5][0], 110, 3, hashMarksArray[5][1], Gfx.COLOR_WHITE); 491 | drawHash(dc, hashMarksArray[10][0], 110, 3, hashMarksArray[10][1], Gfx.COLOR_WHITE); 492 | drawHash(dc, hashMarksArray[20][0], 110, 3, hashMarksArray[20][1], Gfx.COLOR_WHITE); 493 | drawHash(dc, hashMarksArray[25][0], 110, 3, hashMarksArray[25][1], Gfx.COLOR_WHITE); 494 | drawHash(dc, hashMarksArray[35][0], 110, 3, hashMarksArray[35][1], Gfx.COLOR_WHITE); 495 | drawHash(dc, hashMarksArray[40][0], 110, 3, hashMarksArray[40][1], Gfx.COLOR_WHITE); 496 | drawHash(dc, hashMarksArray[50][0], 110, 3, hashMarksArray[50][1], Gfx.COLOR_WHITE); 497 | drawHash(dc, hashMarksArray[55][0], 110, 3, hashMarksArray[55][1], Gfx.COLOR_WHITE); 498 | 499 | drawHash(dc, hashMarksArray[0][0], 110, 5, hashMarksArray[0][1], Gfx.COLOR_WHITE); 500 | drawHash(dc, hashMarksArray[15][0], 110, 5, hashMarksArray[15][1], Gfx.COLOR_WHITE); 501 | drawHash(dc, hashMarksArray[45][0], 110, 5, hashMarksArray[45][1], Gfx.COLOR_WHITE); 502 | 503 | if(!showHeartRate) 504 | { drawHash(dc, hashMarksArray[30][0], 110, 5, hashMarksArray[30][1], Gfx.COLOR_WHITE); } 505 | } 506 | 507 | 508 | function drawDate(dc) 509 | { 510 | var info = Calendar.info(Time.now(), Time.FORMAT_LONG); 511 | var dateStr = Lang.format("$1$ $2$ $3$", [info.day_of_week, info.month, info.day]); 512 | 513 | if (showSecondTime) 514 | { dc.drawText(width_screen/2, height_screen/2 - 60, Gfx.FONT_MEDIUM, dateStr, Gfx.TEXT_JUSTIFY_CENTER); } 515 | else 516 | { dc.drawText(width_screen/2, height_screen/2 - 55, Gfx.FONT_MEDIUM, dateStr, Gfx.TEXT_JUSTIFY_CENTER); } 517 | } 518 | 519 | 520 | function drawDigitalTime(dc, clockTime) 521 | { 522 | if (showSecondTime) 523 | { 524 | var offsetHour = clockTime.hour + secondTimeOffset; 525 | 526 | if (offsetHour > 23) 527 | { offsetHour -= 24; } 528 | else if (offsetHour < 0) 529 | { offsetHour += 24; } 530 | 531 | var ampm = "am"; 532 | if (offsetHour >= 12) 533 | { ampm = "pm"; } 534 | 535 | var timeString = Lang.format("$1$:$2$$3$", [to12hourFormat(offsetHour), clockTime.min.format("%02d"), ampm]); 536 | dc.drawText(width_screen/2, height_screen/2 - 30, Gfx.FONT_SMALL, timeString, Gfx.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); 537 | } 538 | } 539 | 540 | 541 | function drawSunriseSunset(dc) 542 | { 543 | var sc = new SunCalc(); 544 | var lat; 545 | var lon; 546 | var timeStringRise = " --:--"; 547 | var timeStringSet = " --:--"; 548 | 549 | 550 | var loc = Activity.getActivityInfo().currentLocation; 551 | if (loc == null) 552 | { 553 | lat = App.getApp().getProperty(LAT); 554 | lon = App.getApp().getProperty(LON); 555 | } 556 | else 557 | { 558 | lat = loc.toDegrees()[0] * Math.PI / 180.0; 559 | App.getApp().setProperty(LAT, lat); 560 | lon = loc.toDegrees()[1] * Math.PI / 180.0; 561 | App.getApp().setProperty(LON, lon); 562 | } 563 | 564 | // lat = -37.81400 * Math.PI / 180.0; 565 | // lon = 144.96332 * Math.PI / 180.0; 566 | 567 | if(lat != null && lon != null) 568 | { 569 | var ampm; 570 | 571 | var now = new Time.Moment(Time.now().value()); 572 | var sunrise_moment = sc.calculate(now, lat.toDouble(), lon.toDouble(), SUNRISE); 573 | var sunset_moment = sc.calculate(now, lat.toDouble(), lon.toDouble(), SUNSET); 574 | 575 | var timeInfoSunrise = Calendar.info(sunrise_moment, Time.FORMAT_SHORT); 576 | var timeInfoSunset = Calendar.info(sunset_moment, Time.FORMAT_SHORT); 577 | 578 | ampm = "a"; 579 | if (timeInfoSunrise.hour >= 12) 580 | { ampm = "p"; } 581 | timeStringRise = Lang.format("$1$:$2$$3$", [to12hourFormat(timeInfoSunrise.hour), timeInfoSunrise.min.format("%02d"), ampm]); 582 | 583 | ampm = "a"; 584 | if (timeInfoSunset.hour >= 12) 585 | { ampm = "p"; } 586 | timeStringSet = Lang.format("$1$:$2$$3$", [to12hourFormat(timeInfoSunset.hour), timeInfoSunset.min.format("%02d"), ampm]); 587 | } 588 | 589 | dc.drawText(3, height_screen/2 - 14, Gfx.FONT_SMALL, timeStringRise, Gfx.TEXT_JUSTIFY_LEFT|Graphics.TEXT_JUSTIFY_VCENTER); 590 | dc.drawText(3, height_screen/2 + 11, Gfx.FONT_SMALL, timeStringSet, Gfx.TEXT_JUSTIFY_LEFT|Graphics.TEXT_JUSTIFY_VCENTER); 591 | 592 | } 593 | 594 | 595 | function to12hourFormat(hour) 596 | { 597 | var hour12 = hour % 12; 598 | if (hour12 == 0) 599 | { hour12 = 12; } 600 | 601 | return hour12; 602 | } 603 | 604 | 605 | function authenticate(code) { 606 | 607 | proFeatures = true; 608 | 609 | // set proFeatures=false 610 | // insert your authentication requirements here 611 | // then change proFeatures=true if "code" variable is valid 612 | 613 | } 614 | 615 | } 616 | -------------------------------------------------------------------------------- /bin/SnapshotWatch.prg.debug.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | Load your resources here
]]>
588 |
589 | 590 | Restore the state of the app and prepare the view to be shown
]]>
591 |
592 | 593 | 594 | Update the view
]]>
595 |
596 | 597 | The user has just looked at their watch. Timers and animations may be started here.
]]>
598 |
599 | 600 | Terminate any active timers and prepare for slow updates.
]]>
601 |
602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | Draw the watch hand
]]>
617 |
618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | Draw the hash mark symbols
]]>
637 |
638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | Draw the layout
param The context
]]>
676 |
677 |
678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 |
692 | --------------------------------------------------------------------------------