using Toybox.WatchUi; using Toybox.Graphics; using Toybox.System; using Toybox.Lang; using Toybox.Time; using Toybox.Time.Gregorian; using Toybox.Application; class DecimalWatchFaceView extends WatchUi.WatchFace { var isHighPowerMode = true; // Track if we're in high power mode // Custom colors for AMOLED-friendly shadows const VERY_DARK_RED = 0x330000; // #330000 const VERY_DARK_GRAY = 0x333333; // #333333 var useAmoledColors = false; // Whether to use darker colors function initialize() { WatchFace.initialize(); // Check if device likely has AMOLED screen // AMOLED devices typically support always-on display and higher color depths var deviceSettings = System.getDeviceSettings(); // Check if device supports always-on display (common on AMOLED) // or if we can detect high color support if (deviceSettings has :requiresBurnInProtection) { useAmoledColors = deviceSettings.requiresBurnInProtection; } else { // Fallback: use darker colors if device has round screen (most AMOLED watches) // This is a heuristic, but safer to use dark colors on all devices useAmoledColors = true; // Use darker colors by default for burn-in protection } } // Load your resources here function onLayout(dc) { // We draw everything programmatically, no layout needed } // Called when this View is brought to the foreground. Restore // the state of this View and prepare it to be shown. This includes // loading resources into memory. function onShow() { } // Update the view function onUpdate(dc) { // Get the current time var clockTime = System.getClockTime(); var decimalTime = computeDecimalTime(clockTime); // Check settings var useFiveHourMode = Application.Properties.getValue("UseFiveHourMode"); var show12HourShadow = Application.Properties.getValue("Show12HourShadow"); var showNumericTime = Application.Properties.getValue("ShowNumericTime"); var displayTime = decimalTime; var isMorning = true; if (useFiveHourMode) { // Convert 0-10 to 0-5 twice per day if (decimalTime >= 5.0) { displayTime = decimalTime - 5.0; isMorning = false; // Afternoon } else { displayTime = decimalTime; isMorning = true; // Morning } } // Clear the screen dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK); dc.clear(); // Draw the watchface (circle, ticks, numbers) drawWatchFace(dc, useFiveHourMode, isMorning); // Draw digital time displays (before hands so hands appear on top) if (showNumericTime) { // Draw decimal time at bottom drawDigitalTime(dc, decimalTime); // If 12-hour shadow is also enabled, draw traditional time at top if (show12HourShadow) { drawTraditionalTime(dc, clockTime); } } // Draw the hands last (on top of everything) drawHand(dc, displayTime, useFiveHourMode, show12HourShadow, clockTime); } // Called when this View is removed from the screen. Save the // state of this View here. This includes freeing resources from // memory. function onHide() { } // The user has just looked at their watch. Timers and animations may be started here. function onExitSleep() { isHighPowerMode = true; } // Terminate any active timers and prepare for slow updates. function onEnterSleep() { isHighPowerMode = false; } // Compute decimal time from current clock time // Returns a value from 0.0 to 10.0 representing the day's progress function computeDecimalTime(clockTime) { var hour = clockTime.hour; var min = clockTime.min; var sec = clockTime.sec; // Convert to decimal: (hours + minutes/60 + seconds/3600) / 24 * 10 var decimalTime = (hour + (min / 60.0) + (sec / 3600.0)) / 24.0 * 10.0; return decimalTime; } // Draw the watchface circle, tick marks, and numbers function drawWatchFace(dc, useFiveHourMode, isMorning) { var width = dc.getWidth(); var height = dc.getHeight(); var centerX = width / 2; var centerY = height / 2; var radius = (width < height ? width : height) / 2 - 10; dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); // Determine scale based on mode (5 or 10 hour) var maxValue = useFiveHourMode ? 5.0 : 10.0; var tickCount = useFiveHourMode ? 50 : 100; // 0.1 intervals // Draw tick marks at 0.1 intervals (major at whole numbers, minor at 0.1) for (var i = 0; i < tickCount; i++) { var decimalValue = i * 0.1; var angle = (decimalValue / maxValue) * 360.0 - 90.0; // -90 to start at top var angleRad = Math.toRadians(angle); // Determine if this is a major tick (whole number) or minor tick var isMajor = (i % 10 == 0); // Every 10th position is a whole number var tickLength = isMajor ? 15 : 8; // Major ticks are longer var penWidth = isMajor ? 3 : 1; // Major ticks are thicker // Calculate tick mark positions var tickOuterX = centerX + radius * Math.cos(angleRad); var tickOuterY = centerY + radius * Math.sin(angleRad); var tickInnerX = centerX + (radius - tickLength) * Math.cos(angleRad); var tickInnerY = centerY + (radius - tickLength) * Math.sin(angleRad); // Draw tick mark dc.setPenWidth(penWidth); dc.drawLine(tickOuterX, tickOuterY, tickInnerX, tickInnerY); // Draw number only for major ticks if (isMajor) { var numberX = centerX + (radius - 38) * Math.cos(angleRad); var numberY = centerY + (radius - 38) * Math.sin(angleRad); var numberValue = (i / 10).toNumber(); // Position 0-4 or 0-9 if (useFiveHourMode) { // 5-hour mode: show different numbers based on morning/afternoon if (isMorning) { // Morning: show 5,1,2,3,4 (5 at top, then 1,2,3,4) if (numberValue == 0) { numberValue = 5; } // else numberValue stays as 1,2,3,4 } else { // Afternoon: show 10,6,7,8,9 (10 at top, then 6,7,8,9) if (numberValue == 0) { numberValue = 10; } else { numberValue = numberValue + 5; // 1->6, 2->7, 3->8, 4->9 } } } else { // 10-hour mode: show 10 at top instead of 0 if (numberValue == 0) { numberValue = 10; } } dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.drawText( numberX, numberY, Graphics.FONT_MEDIUM, numberValue.toString(), Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER ); } } // Note: Center dot is drawn in drawHand() to ensure it's on top of everything } // Draw hour, minute, and second hands for current decimal time function drawHand(dc, decimalTime, useFiveHourMode, show12HourShadow, clockTime) { var width = dc.getWidth(); var height = dc.getHeight(); var centerX = width / 2; var centerY = height / 2; var radius = (width < height ? width : height) / 2 - 10; // Draw traditional 12-hour shadow hands first (if enabled), so they appear behind if (show12HourShadow) { var hour = clockTime.hour; var minute = clockTime.min; // Calculate traditional 12-hour hand angle var traditional12HourAngle = ((hour % 12) + (minute / 60.0)) / 12.0 * 360.0 - 90.0; var traditional12HourLength = radius - 70; // Same as decimal hour hand // Calculate traditional 60-minute hand angle var traditional60MinuteAngle = (minute / 60.0) * 360.0 - 90.0; var traditional60MinuteLength = radius - 45; // Same as decimal minute hand // Choose colors based on screen type (darker for AMOLED burn-in protection) var shadowGray = useAmoledColors ? VERY_DARK_GRAY : Graphics.COLOR_DK_GRAY; var shadowRed = useAmoledColors ? VERY_DARK_RED : Graphics.COLOR_DK_RED; // Draw traditional minute hand (dark gray) drawSingleHand(dc, centerX, centerY, traditional60MinuteAngle, traditional60MinuteLength, 4, shadowGray); // Draw traditional hour hand (dark red) drawSingleHand(dc, centerX, centerY, traditional12HourAngle, traditional12HourLength, 6, shadowRed); } // Adjust scale based on mode var maxValue = useFiveHourMode ? 5.0 : 10.0; // Calculate hour hand (shows which decimal unit) // In 10-hour mode: one rotation per day // In 5-hour mode: two rotations per day var hourAngle = (decimalTime / maxValue) * 360.0 - 90.0; var hourHandLength = radius - 70; // Shorter hand // Calculate minute hand (shows fractional part) var fractionalPart = decimalTime - decimalTime.toNumber(); // Get decimal part var minuteAngle = fractionalPart * 360.0 - 90.0; var minuteHandLength = radius - 45; // Longer hand // Calculate second hand (shows finer detail) // Only visible in high power mode var multiplier = 100.0; // 0.01 increments var secondFractionalPart = (decimalTime * multiplier) - (decimalTime * multiplier).toNumber(); var secondAngle = secondFractionalPart * 360.0 + 90.0; var secondHandLength = radius - 35; // Longest hand // Draw second hand first (if in high power mode), so it appears behind other hands if (isHighPowerMode) { drawSingleHand(dc, centerX, centerY, secondAngle, secondHandLength, 2, Graphics.COLOR_YELLOW); } // Draw minute hand (longer, thinner) drawSingleHand(dc, centerX, centerY, minuteAngle, minuteHandLength, 4, Graphics.COLOR_WHITE); // Draw hour hand (shorter, wider) drawSingleHand(dc, centerX, centerY, hourAngle, hourHandLength, 6, Graphics.COLOR_RED); // Redraw center dot on top of hands dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.fillCircle(centerX, centerY, 5); } // Helper function to draw a single hand function drawSingleHand(dc, centerX, centerY, angle, handLength, handWidth, color) { var angleRad = Math.toRadians(angle); // Calculate hand tip position var handTipX = centerX + handLength * Math.cos(angleRad); var handTipY = centerY + handLength * Math.sin(angleRad); // Calculate hand base positions (for a triangle/arrow shape) var perpAngleRad1 = angleRad + Math.toRadians(90); var perpAngleRad2 = angleRad - Math.toRadians(90); var baseX1 = centerX + handWidth * Math.cos(perpAngleRad1); var baseY1 = centerY + handWidth * Math.sin(perpAngleRad1); var baseX2 = centerX + handWidth * Math.cos(perpAngleRad2); var baseY2 = centerY + handWidth * Math.sin(perpAngleRad2); // Draw the hand as a filled polygon dc.setColor(color, Graphics.COLOR_TRANSPARENT); dc.fillPolygon([ [handTipX, handTipY], [baseX1, baseY1], [baseX2, baseY2] ]); } // Draw digital display of decimal time function drawDigitalTime(dc, decimalTime) { var width = dc.getWidth(); var height = dc.getHeight(); // Format decimal time to 2 decimal places var timeString = decimalTime.format("%.2f"); // Draw at bottom center dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.drawText( width / 2, height * 0.75, Graphics.FONT_LARGE, timeString, Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER ); } // Draw traditional 12-hour time display function drawTraditionalTime(dc, clockTime) { var width = dc.getWidth(); var height = dc.getHeight(); var hour = clockTime.hour; var minute = clockTime.min; // Convert to 12-hour format var hour12 = hour % 12; if (hour12 == 0) { hour12 = 12; } // Format as HH:MM var timeString = hour12.format("%d") + ":" + minute.format("%02d"); // Choose color based on screen type (darker for AMOLED burn-in protection) var shadowGray = useAmoledColors ? VERY_DARK_GRAY : Graphics.COLOR_DK_GRAY; // Draw at top center in dark gray dc.setColor(shadowGray, Graphics.COLOR_TRANSPARENT); dc.drawText( width / 2, height * 0.25, Graphics.FONT_LARGE, timeString, Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER ); } }