initial version [by claude]

This commit is contained in:
Gyuri Horák 2025-11-03 18:41:28 +01:00
commit bd857a4e52
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG Key ID: 4993F07B3EAE8D38
11 changed files with 609 additions and 0 deletions

View File

@ -0,0 +1,10 @@
{
"permissions": {
"allow": [
"WebSearch",
"WebFetch(domain:github.com)"
],
"deny": [],
"ask": []
}
}

69
.gitignore vendored Normal file
View File

@ -0,0 +1,69 @@
# Garmin Connect IQ Build Artifacts
*.prg
*.iq
bin/
*.debug.xml
# Developer Keys (IMPORTANT: Never commit these!)
*.der
*.pem
developer_key
developer_key.der
# IDE Files
.vscode/
.idea/
*.iml
.settings/
.project
.classpath
# Eclipse/Garmin Plugin
.externalToolBuilders/
# Build directories
build/
target/
out/
# Temporary files
*.tmp
*.bak
*.swp
*~
.DS_Store
Thumbs.db
# Logs
*.log
# Generated resources
gen/
# Simulator data
.simulator/
# Barrel files (if not distributing)
barrels/
# Mac OS
.DS_Store
.AppleDouble
.LSOverride
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
# Linux
*~
.directory
# Compiled source
*.class
*.dll
*.exe
*.o
*.so

131
PLAN-metric-watchface.md Normal file
View File

@ -0,0 +1,131 @@
# Decimal Day Progress Watchface - Implementation Plan
## Concept Overview
Create a joke/novelty Garmin watchface that displays time as a decimal day progress meter instead of traditional 12/24 hour format.
### Key Features
- **10 equal divisions** on the watchface (instead of 12 hours)
- **Single hand** showing day progress as a decimal (0-10)
- **Analog display** with tick marks at each decimal position
- **Optional digital readout** showing exact decimal time
### Time Mapping
- Midnight (00:00) → 0.0
- 6:00 AM → 2.5
- Noon (12:00) → 5.0
- 6:00 PM → 7.5
- Midnight (24:00) → 10.0 (wraps to 0)
## Technical Implementation
### Project Structure
```
MetricWatchFace/
├── manifest.xml # App metadata and device compatibility
├── monkey.jungle # Build configuration
├── resources/
│ ├── drawables/
│ │ └── drawables.xml # Layout definitions
│ ├── strings/
│ │ └── strings.xml # Localization
│ └── settings/
│ └── settings.xml # User settings (if needed)
└── source/
├── MetricWatchFaceApp.mc # Application entry point
└── MetricWatchFaceView.mc # Main watchface view logic
```
### Core Calculation
**Decimal Time Formula:**
```
decimalTime = (currentHour + currentMinute/60.0 + currentSecond/3600.0) / 24.0 * 10.0
```
**Hand Angle Calculation:**
```
handAngle = (decimalTime / 10.0) * 360.0 - 90.0 // -90 to start at top (12 o'clock position)
```
### Drawing Components
1. **Watchface Circle**
- Use `drawCircle()` or `drawArc()` for outline
- Draw 10 tick marks at 36° intervals (360°/10)
2. **Decimal Markers**
- Place numbers 0-9 around the perimeter
- Position 0 at top (traditional 12 o'clock position)
- Position 5 at bottom (traditional 6 o'clock position)
3. **Progress Hand**
- Use `fillPolygon()` to draw a triangle/arrow hand
- Calculate hand coordinates using trigonometry
- Rotate based on current decimal time
4. **Digital Display** (optional)
- Show exact decimal time (e.g., "3.47")
- Position at center or bottom of face
### Key Methods
**MetricWatchFaceView.mc:**
- `initialize()` - Set up initial state
- `onUpdate(dc)` - Main rendering method (called periodically)
- `computeDecimalTime()` - Calculate current decimal time
- `drawWatchFace(dc)` - Draw the analog face and markers
- `drawHand(dc, decimalTime)` - Draw the progress hand
- `drawDigitalTime(dc, decimalTime)` - Optional digital display
### Device Compatibility
Target devices:
- Fenix series (5, 6, 7)
- Forerunner series (245, 645, 945)
- Vivoactive series (3, 4)
- Other modern Garmin watches with Connect IQ support
Considerations:
- Handle different screen sizes/resolutions
- Support both round and semi-round displays
- Test with MIP and AMOLED displays
## Implementation Steps
1. **Project Setup**
- Create manifest.xml with app metadata
- Set up basic directory structure
- Create application entry point
2. **Core Logic**
- Implement decimal time calculation
- Add time update handling
- Create view class structure
3. **Rendering**
- Draw watchface circle and divisions
- Add decimal markers (0-9)
- Implement hand rotation logic
- Add digital display
4. **Testing & Refinement**
- Test in simulator
- Verify calculations at key times
- Optimize drawing performance
- Test on actual device if available
## Future Enhancements (Optional)
- Add date display
- Include battery indicator
- Show step count or other metrics
- Customizable colors via settings
- Alternative hand styles
- Animation effects
## References
- Garmin Connect IQ SDK Documentation
- Swiss Railway Clock example (analog implementation)
- Monkey C API reference for graphics primitives

130
README.md Normal file
View File

@ -0,0 +1,130 @@
# Metric Day Progress Watchface
A novelty Garmin watchface that displays time as decimal day progress instead of traditional 12/24 hour format!
## Concept
Instead of the traditional 12-hour clock, this watchface divides the day into **10 equal parts** and displays your progress through the day as a decimal number from 0 to 10.
### Time Conversions
- **Midnight (00:00)** → 0.0
- **6:00 AM** → 2.5
- **Noon (12:00)** → 5.0
- **6:00 PM** → 7.5
- **End of day (24:00)** → 10.0
## Features
- Analog watchface with 10 divisions (0-9)
- Rotating red hand showing current day progress
- Digital decimal time display
- Clean, minimalist design
- Supports most modern Garmin devices
## Building the Watchface
### Prerequisites
1. **Garmin Connect IQ SDK** - Download from [developer.garmin.com](https://developer.garmin.com/connect-iq/sdk/)
2. **Java Development Kit (JDK)** - OpenJDK recommended
3. **Visual Studio Code** (optional but recommended)
4. **Garmin Monkey C Extension** for VS Code (optional)
### Build Methods
#### Method 1: Using Visual Studio Code
1. Open this folder in VS Code
2. Ensure the Monkey C extension is installed
3. Press the play button in the toolbar
4. Select your target device from the simulator
#### Method 2: Using Command Line
If you have the SDK installed and `$SDK_PATH` set:
```bash
# Build for simulator
$SDK_PATH/bin/monkeyc \
-o MetricWatchFace.prg \
-f monkey.jungle \
-y $SDK_PATH/bin/developer_key
# Run in simulator
$SDK_PATH/bin/connectiq
```
#### Method 3: Using monkeybrains (if available)
```bash
monkeybrains build
monkeybrains run
```
### Deploying to a Real Device
1. Build the `.prg` file using one of the methods above
2. Connect your Garmin device via USB
3. Copy the `.prg` file to the `GARMIN/APPS` folder on your device
4. Safely disconnect the device
5. The watchface should now be available in your watchface selection menu
## Project Structure
```
MetricWatchFace/
├── manifest.xml # App configuration
├── monkey.jungle # Build configuration
├── source/
│ ├── MetricWatchFaceApp.mc # Application entry point
│ └── MetricWatchFaceView.mc # Main watchface logic
└── resources/
├── drawables/
│ ├── drawables.xml # Drawable resources
│ └── launcher_icon.png # App icon (placeholder)
└── strings/
└── strings.xml # String resources
```
## How It Works
The watchface calculates decimal time using the formula:
```
decimalTime = (hours + minutes/60 + seconds/3600) / 24 * 10
```
This value (0.0 to 10.0) is then displayed:
- **Graphically** via a rotating red hand on an analog face
- **Digitally** as a decimal number at the bottom of the screen
## Supported Devices
This watchface supports a wide range of Garmin devices including:
- Fenix series (5, 5 Plus, 6, 7)
- Forerunner series (245, 645, 945, 955)
- Vivoactive series (3, 4)
- Venu series (1, 2, 2 Plus)
See `manifest.xml` for the complete list.
## Notes
- The launcher icon is currently a placeholder - you can replace it with your own PNG image
- The watchface uses a simple black background with white/red elements
- Updates occur every second when active to show smooth hand movement
## Future Enhancements
Potential improvements:
- Add date display
- Battery indicator
- Step count or other fitness metrics
- Customizable colors via settings
- Different hand styles
- AMOLED-optimized always-on mode
## License
This is a fun/joke project - feel free to use and modify as you wish!

65
manifest.xml Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0"?>
<!-- Metric Day Progress Watchface Manifest -->
<iq:manifest xmlns:iq="http://www.garmin.com/xml/connectiq" version="3">
<iq:application entry="MetricWatchFaceApp" id="350d1be0-5312-40bf-bf4d-fffcbd227484" launcherIcon="@Drawables.LauncherIcon" minApiLevel="3.2.0" name="@Strings.AppName" type="watchface" version="1.0.0">
<iq:products>
<!-- Fenix Series -->
<!-- Forerunner Series -->
<!-- Vivoactive Series -->
<!-- Other devices -->
<iq:product id="epix2"/>
<iq:product id="epix2pro42mm"/>
<iq:product id="epix2pro47mm"/>
<iq:product id="epix2pro47mmsystem7preview"/>
<iq:product id="epix2pro51mm"/>
<iq:product id="fenix6"/>
<iq:product id="fenix6pro"/>
<iq:product id="fenix6s"/>
<iq:product id="fenix6spro"/>
<iq:product id="fenix6xpro"/>
<iq:product id="fenix7"/>
<iq:product id="fenix7pro"/>
<iq:product id="fenix7pronowifi"/>
<iq:product id="fenix7s"/>
<iq:product id="fenix7spro"/>
<iq:product id="fenix7x"/>
<iq:product id="fenix7xpro"/>
<iq:product id="fenix7xpronowifi"/>
<iq:product id="fenix843mm"/>
<iq:product id="fenix847mm"/>
<iq:product id="fenix8pro47mm"/>
<iq:product id="fenix8solar47mm"/>
<iq:product id="fenix8solar51mm"/>
<iq:product id="fenixe"/>
<iq:product id="fr255"/>
<iq:product id="fr255m"/>
<iq:product id="fr255s"/>
<iq:product id="fr255sm"/>
<iq:product id="fr265"/>
<iq:product id="fr265s"/>
<iq:product id="fr57042mm"/>
<iq:product id="fr57047mm"/>
<iq:product id="fr645m"/>
<iq:product id="fr945"/>
<iq:product id="fr945lte"/>
<iq:product id="fr955"/>
<iq:product id="fr965"/>
<iq:product id="fr970"/>
<iq:product id="venu2plus"/>
<iq:product id="venu3"/>
<iq:product id="venu3s"/>
<iq:product id="venu441mm"/>
<iq:product id="venu445mm"/>
<iq:product id="vivoactive3m"/>
<iq:product id="vivoactive4"/>
<iq:product id="vivoactive4s"/>
<iq:product id="vivoactive5"/>
<iq:product id="vivoactive6"/>
</iq:products>
<iq:permissions/>
<iq:languages>
<iq:language>eng</iq:language>
</iq:languages>
<iq:barrels/>
</iq:application>
</iq:manifest>

1
monkey.jungle Normal file
View File

@ -0,0 +1 @@
project.manifest = manifest.xml

View File

@ -0,0 +1,3 @@
<drawables>
<bitmap id="LauncherIcon" filename="launcher_icon.png" />
</drawables>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,3 @@
<strings>
<string id="AppName">Metric Day</string>
</strings>

View File

@ -0,0 +1,23 @@
using Toybox.Application;
using Toybox.WatchUi;
class MetricWatchFaceApp extends Application.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 MetricWatchFaceView() ];
}
}

View File

@ -0,0 +1,174 @@
using Toybox.WatchUi;
using Toybox.Graphics;
using Toybox.System;
using Toybox.Lang;
using Toybox.Time;
using Toybox.Time.Gregorian;
class MetricWatchFaceView extends WatchUi.WatchFace {
function initialize() {
WatchFace.initialize();
}
// 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);
// Clear the screen
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
dc.clear();
// Draw the watchface
drawWatchFace(dc);
// Draw the hand
drawHand(dc, decimalTime);
// Draw digital time display
drawDigitalTime(dc, decimalTime);
}
// 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() {
}
// Terminate any active timers and prepare for slow updates.
function onEnterSleep() {
}
// 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) {
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 outer circle
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
dc.setPenWidth(3);
dc.drawCircle(centerX, centerY, radius);
// Draw tick marks and numbers for each decimal position (0-9)
dc.setPenWidth(2);
for (var i = 0; i < 10; i++) {
var angle = (i / 10.0) * 360.0 - 90.0; // -90 to start at top
var angleRad = Math.toRadians(angle);
// Calculate tick mark positions
var tickOuterX = centerX + radius * Math.cos(angleRad);
var tickOuterY = centerY + radius * Math.sin(angleRad);
var tickInnerX = centerX + (radius - 15) * Math.cos(angleRad);
var tickInnerY = centerY + (radius - 15) * Math.sin(angleRad);
// Draw tick mark
dc.drawLine(tickOuterX, tickOuterY, tickInnerX, tickInnerY);
// Draw number
var numberX = centerX + (radius - 35) * Math.cos(angleRad);
var numberY = centerY + (radius - 35) * Math.sin(angleRad);
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
dc.drawText(
numberX,
numberY,
Graphics.FONT_MEDIUM,
i.toString(),
Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER
);
}
// Draw center dot
dc.fillCircle(centerX, centerY, 5);
}
// Draw the hand pointing to current decimal time
function drawHand(dc, decimalTime) {
var width = dc.getWidth();
var height = dc.getHeight();
var centerX = width / 2;
var centerY = height / 2;
var radius = (width < height ? width : height) / 2 - 10;
// Calculate hand angle (0-10 maps to 0-360 degrees, starting at top)
var angle = (decimalTime / 10.0) * 360.0 - 90.0; // -90 to start at top
var angleRad = Math.toRadians(angle);
// Hand length (slightly shorter than radius to not overlap with numbers)
var handLength = radius - 50;
// 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 handWidth = 6;
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(Graphics.COLOR_RED, 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
);
}
}