You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
489 lines
16 KiB
489 lines
16 KiB
using Toybox.Graphics as Gfx; |
|
using Toybox.System as Sys; |
|
using Toybox.Lang as Lang; |
|
using Toybox.Math as Math; |
|
using Toybox.Time as Time; |
|
using Toybox.Time.Gregorian as Calendar; |
|
using Toybox.WatchUi as Ui; |
|
using Toybox.Application as App; |
|
using Toybox.ActivityMonitor as ActMon; |
|
using Toybox.SensorHistory as Sensor; |
|
using Toybox.Activity as Activity; |
|
using Toybox.UserProfile as User; |
|
|
|
enum |
|
{ |
|
LAT, |
|
LON |
|
} |
|
|
|
|
|
class SnapshotWatchView extends Ui.WatchFace { |
|
|
|
var usePreferences = true; |
|
var showHeartRate = true; |
|
var showSteps = true; |
|
var showRiseSet = false; |
|
var showSecondTime = false; |
|
var secondTimeOffset = 0; |
|
|
|
var graphLength = 240; |
|
var arrayColours = new [11]; |
|
var graphColour = 0; |
|
var useZonesColour = true; |
|
var heartRateZones; |
|
var showMoveBar = false; |
|
|
|
var background_color = Gfx.COLOR_BLACK; |
|
// var background_color = Gfx.COLOR_BLUE; |
|
var mainTextColor = Gfx.COLOR_WHITE; |
|
|
|
var showSeconds = false; |
|
var width_screen, height_screen; |
|
var hashMarksArray = new [60]; |
|
|
|
var heartNow; |
|
var heartMin = 1000; |
|
var heartMax = 0; |
|
|
|
// var proFeatures = true; |
|
|
|
public function initialize() { |
|
Ui.WatchFace.initialize(); |
|
} |
|
|
|
//! Load your resources here |
|
function onLayout(dc) { |
|
|
|
//get screen dimensions |
|
width_screen = dc.getWidth(); |
|
height_screen = dc.getHeight(); |
|
|
|
//colours and zones |
|
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]; |
|
heartRateZones = User.getHeartRateZones(User.getCurrentSport()); |
|
// heartRateZones = [98, 127, 146, 166, 185, 195]; |
|
|
|
//get hash marks position |
|
for(var i = 0; i < 60; i+=1) |
|
{ |
|
hashMarksArray[i] = new [2]; |
|
hashMarksArray[i][0] = (i / 60.0) * Math.PI * 2; |
|
|
|
if(i != 0 && i != 15 && i != 30 && i != 45) |
|
{ hashMarksArray[i][1] = -95; } |
|
else |
|
{ hashMarksArray[i][1] = -85; } |
|
} |
|
|
|
setLayout(Rez.Layouts.WatchFace(dc)); |
|
} |
|
|
|
//! Restore the state of the app and prepare the view to be shown |
|
function onShow() { |
|
} |
|
|
|
//! Update the view |
|
function onUpdate(dc) { |
|
//var bgImage = Ui.loadResource(Rez.Drawables.BackgroundImage); |
|
var code = "0"; |
|
|
|
if (usePreferences) |
|
{ |
|
code = Application.getApp().getProperty("code"); |
|
showHeartRate = Application.getApp().getProperty("showHeartRate"); |
|
graphLength = Application.getApp().getProperty("graphLength"); |
|
graphColour = Application.getApp().getProperty("graphColour"); |
|
useZonesColour = Application.getApp().getProperty("useZonesColour"); |
|
showMoveBar = Application.getApp().getProperty("showMoveBar"); |
|
showSteps = Application.getApp().getProperty("showSteps"); |
|
showRiseSet = Application.getApp().getProperty("showRiseSet"); |
|
showSecondTime = Application.getApp().getProperty("showSecondTime"); |
|
secondTimeOffset = Application.getApp().getProperty("secondTimeOffset"); |
|
} |
|
|
|
// authenticate(code); |
|
|
|
// if (!proFeatures) |
|
// { |
|
// showSteps = true; |
|
// showRiseSet = false; |
|
// showSecondTime = false; |
|
// } |
|
|
|
// if (showSecondTime) |
|
// { |
|
// if (secondTimeOffset <= 24 && secondTimeOffset >= -24) |
|
// { |
|
// secondTimeOffset = secondTimeOffset.toNumber(); |
|
// } |
|
// else |
|
// { |
|
// showSecondTime = false; |
|
// secondTimeOffset = 0; |
|
// } |
|
// } |
|
|
|
// Clear screen |
|
dc.setColor(background_color, Gfx.COLOR_WHITE); |
|
dc.fillRectangle(0,0, width_screen, height_screen); |
|
//dc.drawBitmap(0, 0, Ui.loadResource(Rez.Drawables.BackgroundImage)); |
|
|
|
//var myActivity = Activity.getActivityInfo(); |
|
heartNow = Activity.getActivityInfo().currentHeartRate; |
|
|
|
// Plot heart rate graph |
|
//plotHRgraph(dc); |
|
|
|
// Draw hash marks |
|
drawHashMarks(dc); |
|
|
|
// Set text colour for the remaining information |
|
dc.setColor(mainTextColor, Gfx.COLOR_TRANSPARENT); |
|
|
|
// Show cur/min/max HR values (recorded when plotting graph, above) |
|
if (showHeartRate) |
|
{ |
|
if (heartNow == null) |
|
{ dc.drawText(width_screen/2, height_screen/2 + 70, Gfx.FONT_SMALL, "-- bpm", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); } |
|
else |
|
{ dc.drawText(width_screen/2, height_screen/2 + 70, Gfx.FONT_SMALL, Lang.format("$1$ bpm", [heartNow]), Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); } |
|
} |
|
|
|
// Show date |
|
dc.setColor(Gfx.COLOR_DK_BLUE, Gfx.COLOR_TRANSPARENT); |
|
dc.drawCircle(width_screen/2-50, height_screen/2, 32); |
|
dc.setColor(mainTextColor, Gfx.COLOR_TRANSPARENT); |
|
drawDate(dc); |
|
|
|
// Show Status Icons |
|
var offset = 8; |
|
var heightOffset = 75; |
|
var spreadOffset = offset*2; |
|
dc.setColor(Gfx.COLOR_DK_BLUE, Gfx.COLOR_TRANSPARENT); |
|
dc.drawEllipse(width_screen/2, height_screen/2-heightOffset+6, 37, 12); |
|
dc.setColor(mainTextColor, Gfx.COLOR_TRANSPARENT); |
|
// Show bluetooth icon |
|
if (Sys.getDeviceSettings().phoneConnected) |
|
{ dc.drawBitmap(width_screen/2-offset-4, height_screen/2-heightOffset, Ui.loadResource(Rez.Drawables.BluetoothCon)); } |
|
else |
|
{ dc.drawBitmap(width_screen/2-offset-4, height_screen/2-heightOffset, Ui.loadResource(Rez.Drawables.BluetoothDC)); } |
|
// Show alarm icon |
|
if (Sys.getDeviceSettings().alarmCount > 0) |
|
{ dc.drawBitmap(width_screen/2-offset-spreadOffset-4, height_screen/2-heightOffset, Ui.loadResource(Rez.Drawables.AlarmIconSet)); } |
|
else |
|
{ dc.drawBitmap(width_screen/2-offset-spreadOffset-4, height_screen/2-heightOffset, Ui.loadResource(Rez.Drawables.AlarmIconClr)); } |
|
// Show do not disturb icon |
|
if (Sys.getDeviceSettings().doNotDisturb) |
|
{ dc.drawBitmap(width_screen/2+offset+spreadOffset-4, height_screen/2-heightOffset, Ui.loadResource(Rez.Drawables.MuteIcon)); } |
|
else |
|
{ dc.drawBitmap(width_screen/2+offset+spreadOffset-4, height_screen/2-heightOffset, Ui.loadResource(Rez.Drawables.VolumeIcon)); } |
|
// Show notification count icon |
|
var numNotifications = Sys.getDeviceSettings().notificationCount; |
|
if (numNotifications >= 10) { spreadOffset += 2; } |
|
dc.drawBitmap(width_screen/2+offset-4, height_screen/2-heightOffset, Ui.loadResource(Rez.Drawables.NotificationIcon)); |
|
if (numNotifications > 0) { |
|
dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_TRANSPARENT); |
|
dc.drawText(width_screen/2+offset+10-4, height_screen/2-heightOffset+5, Gfx.FONT_XTINY, numNotifications, Graphics.TEXT_JUSTIFY_RIGHT|Graphics.TEXT_JUSTIFY_VCENTER); |
|
dc.setColor(mainTextColor, Gfx.COLOR_TRANSPARENT); |
|
} |
|
|
|
// Show Battery |
|
var battery = Sys.getSystemStats().battery; |
|
offset = 40; |
|
heightOffset = 7; |
|
dc.setColor(Gfx.COLOR_DK_BLUE, Gfx.COLOR_TRANSPARENT); |
|
dc.drawCircle(width_screen/2+offset+13, height_screen/2, 26); |
|
dc.setColor(mainTextColor, Gfx.COLOR_TRANSPARENT); |
|
// if (battery == 100) { offset -= 2; } |
|
if (battery >= 90) { |
|
// offset += 4; |
|
dc.drawBitmap(width_screen/2+offset+1, height_screen/2+3-heightOffset, Ui.loadResource(Rez.Drawables.BatteryFullIcon)); |
|
} |
|
else if (battery >= 80) { |
|
dc.drawBitmap(width_screen/2+offset+1, height_screen/2+3-heightOffset, Ui.loadResource(Rez.Drawables.Battery80Icon)); |
|
} |
|
else if (battery >= 60) { |
|
dc.drawBitmap(width_screen/2+offset+1, height_screen/2+3-heightOffset, Ui.loadResource(Rez.Drawables.Battery60Icon)); |
|
} |
|
else if (battery >= 40) { |
|
dc.drawBitmap(width_screen/2+offset+1, height_screen/2+3-heightOffset, Ui.loadResource(Rez.Drawables.Battery40Icon)); |
|
} |
|
else if (battery >= 20) { |
|
dc.drawBitmap(width_screen/2+offset+1, height_screen/2+3-heightOffset, Ui.loadResource(Rez.Drawables.Battery20Icon)); |
|
} |
|
else { |
|
dc.drawBitmap(width_screen/2+offset+1, height_screen/2+3-heightOffset, Ui.loadResource(Rez.Drawables.Battery0Icon)); |
|
} |
|
dc.drawText(width_screen/2+offset+15, height_screen/2-3-heightOffset, Gfx.FONT_XTINY, Lang.format("$1$%", [battery.format("%2d")]), Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); |
|
|
|
|
|
// Show steps |
|
dc.drawBitmap(width_screen/2-37, height_screen/2 - 58, Ui.loadResource(Rez.Drawables.ShoeIcon)); |
|
dc.drawText(width_screen/2, height_screen/2 - 45, Gfx.FONT_SMALL, ActMon.getInfo().steps, Graphics.TEXT_JUSTIFY_LEFT|Graphics.TEXT_JUSTIFY_VCENTER); |
|
//dc.drawText(width_screen/2, height_screen/2 + 30, Gfx.FONT_SMALL, ActMon.getInfo().stepGoal, Graphics.TEXT_JUSTIFY_RIGHT|Graphics.TEXT_JUSTIFY_VCENTER); |
|
|
|
if (showRiseSet) |
|
{ |
|
// Show sunrise and sunset |
|
drawSunriseSunset(dc); |
|
} |
|
|
|
// Show second (digital) time |
|
drawDigitalTime(dc, Sys.getClockTime()); |
|
// Draw analogue clock hands |
|
drawHands(dc, Sys.getClockTime().hour, Sys.getClockTime().min, Sys.getClockTime().sec); |
|
|
|
} |
|
|
|
|
|
//! The user has just looked at their watch. Timers and animations may be started here. |
|
function onExitSleep() { |
|
showSeconds = true; |
|
} |
|
|
|
|
|
//! Terminate any active timers and prepare for slow updates. |
|
function onEnterSleep() { |
|
showSeconds = false; |
|
requestUpdate(); |
|
} |
|
|
|
//! Draw the watch hand |
|
function drawHand(dc, angle, whichHand, width, handColour) |
|
{ |
|
dc.setColor(handColour, Gfx.COLOR_TRANSPARENT); |
|
|
|
var length, r1, r2, r3, r4, deflect1, deflect2; |
|
|
|
var centerX = width_screen/2; |
|
var centerY = height_screen/2; |
|
|
|
if (whichHand == 0) //hour hand |
|
{ |
|
length = 0.6*centerX; |
|
r1 = 0.0*length; |
|
r2 = 0.39*length; |
|
r3 = 0.49*length; |
|
r4 = 1.1*length; |
|
deflect1 = 0.10*width; |
|
deflect2 = 0.08*width; |
|
} |
|
else //minute hand |
|
{ |
|
length = 1.0*centerX; |
|
r1 = 0.0*length; |
|
r2 = 0.37*length; |
|
r3 = 0.47*length; |
|
r4 = 1.2*length; |
|
deflect1 = 0.10*width; |
|
deflect2 = 0.08*width; |
|
} |
|
|
|
var coords = [ |
|
[centerX + r1 * Math.sin(angle) , centerY - r1 * Math.cos(angle)], |
|
[centerX + r2 * Math.sin(angle+deflect1) , centerY - r2 * Math.cos(angle+deflect1)], |
|
[centerX + r3 * Math.sin(angle+deflect2) , centerY - r3 * Math.cos(angle+deflect2)], |
|
[centerX + r4 * Math.sin(angle) , centerY - r4 * Math.cos(angle)], |
|
[centerX + r3 * Math.sin(angle-deflect2) , centerY - r3 * Math.cos(angle-deflect2)], |
|
[centerX + r2 * Math.sin(angle-deflect1) , centerY - r2 * Math.cos(angle-deflect1)], |
|
[centerX + r1 * Math.sin(angle) , centerY - r1 * Math.cos(angle)] |
|
]; |
|
|
|
dc.fillPolygon(coords); |
|
|
|
} |
|
|
|
|
|
function drawHands(dc, clock_hour, clock_min, clock_sec) |
|
{ |
|
var hour, min, sec; |
|
|
|
// Draw the hour hand - convert to minutes then compute angle |
|
hour = ( ( ( clock_hour % 12 ) * 60 ) + clock_min ); // hour = 2*60.0; |
|
hour = hour / (12 * 60.0) * Math.PI * 2; |
|
drawHand(dc, hour, 0, 2.5, Gfx.COLOR_DK_BLUE); |
|
drawHand(dc, hour, 0, 1.6, Gfx.COLOR_LT_GRAY); |
|
|
|
// Draw the minute hand |
|
min = ( clock_min / 60.0); // min = 40/60.0; |
|
min = min * Math.PI * 2; |
|
drawHand(dc, min, 1, 1.7, Gfx.COLOR_DK_BLUE); |
|
drawHand(dc, min, 1, 1.0, Gfx.COLOR_LT_GRAY); |
|
|
|
// Draw the seconds hand (use hash graphic here) |
|
if(showSeconds) |
|
{ |
|
sec = ( clock_sec / 60.0) * Math.PI * 2; |
|
drawHash(dc, sec, width_screen/2, 4, 25, Gfx.COLOR_DK_BLUE); |
|
drawHash(dc, sec, width_screen/2, 2, 25, Gfx.COLOR_LT_GRAY); |
|
} |
|
|
|
// Draw the inner circle |
|
dc.setColor(Gfx.COLOR_DK_BLUE, background_color); |
|
dc.fillCircle(width_screen/2, height_screen/2, 6); |
|
dc.setColor(background_color,background_color); |
|
dc.drawCircle(width_screen/2, height_screen/2, 6); |
|
dc.fillCircle(width_screen/2, height_screen/2, 2); |
|
} |
|
|
|
|
|
function drawHash(dc, angle, length, width, overheadLine, handColour) |
|
{ |
|
dc.setColor(handColour, Gfx.COLOR_TRANSPARENT); |
|
|
|
var centerX = width_screen/2; |
|
var centerY = height_screen/2; |
|
|
|
var result = new [4]; |
|
var cos = Math.cos(angle); |
|
var sin = Math.sin(angle); |
|
|
|
var coords = [ |
|
[-(width/2), 0 + overheadLine], |
|
[-(width/2), -length], |
|
[width/2, -length], |
|
[width/2, 0 + overheadLine] |
|
]; |
|
|
|
for (var i = 0; i < 4; i += 1) |
|
{ |
|
var x = (coords[i][0] * cos) - (coords[i][1] * sin); |
|
var y = (coords[i][0] * sin) + (coords[i][1] * cos); |
|
result[i] = [ centerX + x, centerY + y]; |
|
} |
|
|
|
dc.fillPolygon(result); |
|
|
|
} |
|
|
|
|
|
//! Draw the hash mark symbols |
|
function drawHashMarks(dc) |
|
{ |
|
drawHash(dc, hashMarksArray[5][0], 110, 3, hashMarksArray[5][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[10][0], 110, 3, hashMarksArray[10][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[20][0], 110, 3, hashMarksArray[20][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[25][0], 110, 3, hashMarksArray[25][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[35][0], 110, 3, hashMarksArray[35][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[40][0], 110, 3, hashMarksArray[40][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[50][0], 110, 3, hashMarksArray[50][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[55][0], 110, 3, hashMarksArray[55][1], Gfx.COLOR_WHITE); |
|
|
|
drawHash(dc, hashMarksArray[0][0], 110, 5, hashMarksArray[0][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[15][0], 110, 5, hashMarksArray[15][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, hashMarksArray[45][0], 110, 5, hashMarksArray[45][1], Gfx.COLOR_WHITE); |
|
drawHash(dc, Math.PI, 110, 5, hashMarksArray[0][1], Gfx.COLOR_WHITE); |
|
|
|
if(!showHeartRate) |
|
{ drawHash(dc, hashMarksArray[30][0], 110, 5, hashMarksArray[30][1], Gfx.COLOR_WHITE); } |
|
} |
|
|
|
|
|
function drawDate(dc) |
|
{ |
|
var info = Calendar.info(Time.now(), Time.FORMAT_LONG); |
|
var dateStr = Lang.format("$1$ $2$", [info.month, info.day]); |
|
|
|
dc.drawText(width_screen/2-50, height_screen/2 - 30, Gfx.FONT_TINY, info.day_of_week, Gfx.TEXT_JUSTIFY_CENTER); |
|
dc.drawText(width_screen/2-50, height_screen/2 - 13, Gfx.FONT_TINY, dateStr, Gfx.TEXT_JUSTIFY_CENTER); |
|
dc.drawText(width_screen/2-50, height_screen/2 + 6, Gfx.FONT_TINY, info.year-2000, Gfx.TEXT_JUSTIFY_CENTER); |
|
} |
|
|
|
|
|
function drawDigitalTime(dc, clockTime) |
|
{ |
|
if (showSecondTime) |
|
{ |
|
var offsetHour = clockTime.hour + secondTimeOffset; |
|
|
|
if (offsetHour > 23) |
|
{ offsetHour -= 24; } |
|
else if (offsetHour < 0) |
|
{ offsetHour += 24; } |
|
|
|
var ampm = "AM"; |
|
if (offsetHour >= 12) |
|
{ ampm = "PM"; } |
|
|
|
var timeString = Lang.format("$1$:$2$ $3$", [to12hourFormat(offsetHour), clockTime.min.format("%02d"), ampm]); |
|
dc.drawText(width_screen/2, height_screen/2 + 50, Gfx.FONT_SMALL, timeString, Gfx.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); |
|
} |
|
} |
|
|
|
|
|
function drawSunriseSunset(dc) |
|
{ |
|
var sc = new SunCalc(); |
|
var lat; |
|
var lon; |
|
var timeStringRise = " --:--"; |
|
var timeStringSet = " --:--"; |
|
|
|
|
|
var loc = Activity.getActivityInfo().currentLocation; |
|
if (loc == null) |
|
{ |
|
lat = App.getApp().getProperty(LAT); |
|
lon = App.getApp().getProperty(LON); |
|
} |
|
else |
|
{ |
|
lat = loc.toDegrees()[0] * Math.PI / 180.0; |
|
App.getApp().setProperty(LAT, lat); |
|
lon = loc.toDegrees()[1] * Math.PI / 180.0; |
|
App.getApp().setProperty(LON, lon); |
|
} |
|
|
|
// lat = -37.81400 * Math.PI / 180.0; |
|
// lon = 144.96332 * Math.PI / 180.0; |
|
|
|
if(lat != null && lon != null) |
|
{ |
|
var ampm; |
|
|
|
var now = new Time.Moment(Time.now().value()); |
|
var sunrise_moment = sc.calculate(now, lat.toDouble(), lon.toDouble(), SUNRISE); |
|
var sunset_moment = sc.calculate(now, lat.toDouble(), lon.toDouble(), SUNSET); |
|
|
|
var timeInfoSunrise = Calendar.info(sunrise_moment, Time.FORMAT_SHORT); |
|
var timeInfoSunset = Calendar.info(sunset_moment, Time.FORMAT_SHORT); |
|
|
|
ampm = "a"; |
|
if (timeInfoSunrise.hour >= 12) |
|
{ ampm = "p"; } |
|
timeStringRise = Lang.format("$1$:$2$$3$", [to12hourFormat(timeInfoSunrise.hour), timeInfoSunrise.min.format("%02d"), ampm]); |
|
|
|
ampm = "a"; |
|
if (timeInfoSunset.hour >= 12) |
|
{ ampm = "p"; } |
|
timeStringSet = Lang.format("$1$:$2$$3$", [to12hourFormat(timeInfoSunset.hour), timeInfoSunset.min.format("%02d"), ampm]); |
|
} |
|
|
|
dc.drawText(3, height_screen/2 - 14, Gfx.FONT_SMALL, timeStringRise, Gfx.TEXT_JUSTIFY_LEFT|Graphics.TEXT_JUSTIFY_VCENTER); |
|
dc.drawText(3, height_screen/2 + 11, Gfx.FONT_SMALL, timeStringSet, Gfx.TEXT_JUSTIFY_LEFT|Graphics.TEXT_JUSTIFY_VCENTER); |
|
|
|
} |
|
|
|
|
|
function to12hourFormat(hour) |
|
{ |
|
var hour12 = hour % 12; |
|
if (hour12 == 0) |
|
{ hour12 = 12; } |
|
|
|
return hour12; |
|
} |
|
|
|
|
|
// function authenticate(code) { |
|
|
|
// proFeatures = true; |
|
|
|
// // set proFeatures=false |
|
// // insert your authentication requirements here |
|
// // then change proFeatures=true if "code" variable is valid |
|
|
|
// } |
|
|
|
}
|
|
|