initial commit

This commit is contained in:
2025-10-09 14:37:45 +03:00
commit d75a0b235d
15 changed files with 341 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
bin/

35
manifest.xml Normal file
View File

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!-- This is a generated file. It is highly recommended that you DO NOT edit this file. -->
<iq:manifest version="3" xmlns:iq="http://www.garmin.com/xml/connectiq">
<!--
Use "Monkey C: Edit Application" from the Visual Studio Code command palette
to update the application attributes.
-->
<iq:application id="87cf1f68-dcef-4751-bf6f-9337d59b08dd" type="watchface" name="@Strings.AppName" entry="wfApp" launcherIcon="@Drawables.LauncherIcon" minApiLevel="5.2.0">
<!--
Use the following from the Visual Studio Code comand palette to edit
the build targets:
"Monkey C: Set Products by Product Category" - Lets you add all products
that belong to the same product category
"Monkey C: Edit Products" - Lets you add or remove any product
-->
<iq:products>
<iq:product id="fenix8pro47mm"/>
</iq:products>
<!--
Use "Monkey C: Edit Permissions" from the Visual Studio Code command
palette to update permissions.
-->
<iq:permissions/>
<!--
Use "Monkey C: Edit Languages" from the Visual Studio Code command
palette to edit your compatible language list.
-->
<iq:languages/>
<!--
Use "Monkey C: Configure Monkey Barrel" from the Visual Studio Code
command palette to edit the included barrels.
-->
<iq:barrels/>
</iq:application>
</iq:manifest>

1
monkey.jungle Executable file
View File

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

View File

@ -0,0 +1,3 @@
<drawables xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://developer.garmin.com/downloads/connect-iq/resources.xsd">
<bitmap id="LauncherIcon" filename="launcher_icon.svg" dithering="none" />
</drawables>

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" fill="#000000"/>
<path d="M12.1941 10.8471L16.1353 7.30588L16.9235 8.17646L13.1059 11.6059C13.1471 11.7294 13.1765 11.8588 13.1765 12C13.1765 12.6471 12.6471 13.1765 12 13.1765C11.701 13.1765 11.4272 13.0634 11.219 12.878L5.90332 15.9461L5.60926 15.4367L10.8899 12.3888C10.8469 12.2669 10.8235 12.1361 10.8235 12C10.8235 11.9824 10.8265 11.9662 10.8294 11.95C10.8324 11.9338 10.8353 11.9176 10.8353 11.9L8.12353 10.0471L8.78235 9.07058L11.5059 10.9353C11.6588 10.8647 11.8235 10.8235 12 10.8235C12.0647 10.8235 12.1294 10.8353 12.1941 10.8471Z" fill="#F4F4F4"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM11.4118 20.2146V18.4706H12.5882V20.2146C16.6676 19.9267 19.9267 16.6676 20.2146 12.5882H18.4706V11.4118H20.2146C19.9267 7.33237 16.6676 4.07329 12.5882 3.78539V5.52941H11.4118V3.78539C7.33237 4.07329 4.07329 7.33237 3.78539 11.4118H5.52941V12.5882H3.78539C4.07329 16.6676 7.33237 19.9267 11.4118 20.2146Z" fill="#F4F4F4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

4
resources/layouts/layout.xml Executable file
View File

@ -0,0 +1,4 @@
<layout id="WatchFace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://developer.garmin.com/downloads/connect-iq/resources.xsd">
<drawable class="Background" />
<label id="TimeLabel" x="center" y="center" font="Graphics.FONT_LARGE" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_BLUE" />
</layout>

View File

@ -0,0 +1,7 @@
<properties xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://developer.garmin.com/downloads/connect-iq/resources.xsd">
<property id="BackgroundColor" type="number">0x000000</property>
<property id="ForegroundColor" type="number">0xFF0000</property>
<property id="UseMilitaryFormat" type="boolean">false</property>
</properties>

25
resources/settings/settings.xml Executable file
View File

@ -0,0 +1,25 @@
<settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://developer.garmin.com/downloads/connect-iq/resources.xsd">
<setting propertyKey="@Properties.BackgroundColor" title="@Strings.BackgroundColorTitle">
<settingConfig type="list">
<listEntry value="0x000000">@Strings.ColorBlack</listEntry>
<listEntry value="0x555555">@Strings.ColorDarkGray</listEntry>
<listEntry value="0xAAAAAA">@Strings.ColorLightGray</listEntry>
<listEntry value="0xFFFFFF">@Strings.ColorWhite</listEntry>
</settingConfig>
</setting>
<setting propertyKey="@Properties.ForegroundColor" title="@Strings.ForegroundColorTitle">
<settingConfig type="list">
<listEntry value="0x000000">@Strings.ColorBlack</listEntry>
<listEntry value="0x0000FF">@Strings.ColorBlue</listEntry>
<listEntry value="0xFF0000">@Strings.ColorRed</listEntry>
<listEntry value="0xFFFFFF">@Strings.ColorWhite</listEntry>
</settingConfig>
</setting>
<setting propertyKey="@Properties.UseMilitaryFormat" title="@Strings.MilitaryFormatTitle">
<settingConfig type="boolean" />
</setting>
</settings>

View File

@ -0,0 +1,16 @@
<strings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://developer.garmin.com/downloads/connect-iq/resources.xsd">
<string id="AppName">wf</string>
<string id="BackgroundColorTitle">Background Color</string>
<string id="ForegroundColorTitle">Foreground Color</string>
<string id="MilitaryFormatTitle">Military Format for 24 Hour Time</string>
<string id="ColorBlack">Black</string>
<string id="ColorDarkGray">Dark Gray</string>
<string id="ColorLightGray">Light Gray</string>
<string id="ColorWhite">White</string>
<string id="ColorBlue">Blue</string>
<string id="ColorRed">Red</string>
</strings>

47
source/Hands/Hands.mc Normal file
View File

@ -0,0 +1,47 @@
import Toybox.Graphics;
import Toybox.Lang;
import Toybox.System;
import Toybox.WatchUi;
class Hands extends Drawable {
var CenterShift as [Float, Float];
enum HandType {
HOURS,
MINUTES,
SECONDS,
}
typedef HandsParams as {
:CenterShift as [Float, Float],
};
function initialize(options as HandsParams) {
WatchUi.Drawable.initialize({});
CenterShift = getOrElse(options[:CenterShift], [0.0, 0.0]);
}
function draw(dc as Dc) as Void {
var now = System.getClockTime();
var center = getCenter(dc);
var length = min(center[0], center[1]);
var hourAngle = (now.hour % 12 + now.min / 60.0) * 30.0;
drawHand(dc, center[0], center[1], hourAngle, length, HOURS);
var minutesAngle = now.min * 6.0;
drawHand(dc, center[0], center[1], minutesAngle, length, MINUTES);
var secondsAngle = now.sec * 6.0;
drawHand(dc, center[0], center[1], secondsAngle, length, SECONDS);
}
function drawHand(dc as Dc, x as Float, y as Float, angle as Float, length as Float, handType as HandType) as Void {}
function getCenter(dc as Dc) as [Float, Float] {
return [dc.getWidth() / 2.0 + CenterShift[0], dc.getHeight() / 2.0 + CenterShift[1]];
}
}

View File

@ -0,0 +1,48 @@
import Toybox.Graphics;
import Toybox.Lang;
class SimpleHands extends Hands {
var mColor as ColorType;
var mSecondsColor as ColorType;
typedef SimpleHandsParams as {
:HandsParams as Hands.HandsParams,
:Color as ColorType,
:SecondsColor as ColorType,
};
function initialize(options as SimpleHandsParams) {
Hands.initialize(getOrElse(options[:HandsParams], {}));
mColor = getOrElse(options[:Color], Graphics.COLOR_WHITE);
mSecondsColor = getOrElse(options[:SecondsColor], Graphics.COLOR_RED);
}
function drawHand(dc as Dc, x as Float, y as Float, angle as Float, length as Float, handType as Hands.HandType) as Void {
var rad = (angle - 90) * Math.PI / 180.0;
var color = getColor(handType);
length *= getLenght(handType);
dc.setColor(color, color);
dc.drawLine(x, y, x + length * Math.cos(rad), y + length * Math.sin(rad));
}
private function getColor(handType as Hands.HandType) as ColorType {
switch (handType) {
case Hands.SECONDS:
return mSecondsColor;
default:
return mColor;
}
}
private function getLenght(handType as Hands.HandType) as Float {
switch (handType) {
case Hands.HOURS:
return 0.6;
default:
return 0.9;
}
}
}

20
source/Utils.mc Normal file
View File

@ -0,0 +1,20 @@
import Toybox.Lang;
typedef Numeric as Number or Float or Long or Double;
// no types here, because this is generic, which are not supported by language
function getOrElse(value, defaultValue) {
if (value == null) {
return defaultValue;
} else {
return value;
}
}
function min(left as Numeric, right as Numeric) as Numeric {
if (left < right) {
return left;
} else {
return right;
}
}

33
source/wfApp.mc Normal file
View File

@ -0,0 +1,33 @@
import Toybox.Application;
import Toybox.Lang;
import Toybox.WatchUi;
class wfApp extends Application.AppBase {
function initialize() {
AppBase.initialize();
}
// onStart() is called on application start up
function onStart(state as Dictionary?) as Void {
}
// onStop() is called when your application is exiting
function onStop(state as Dictionary?) as Void {
}
// Return the initial view of your application here
function getInitialView() as [Views] or [Views, InputDelegates] {
return [ new wfView() ];
}
// New app settings have been received so trigger a UI update
function onSettingsChanged() as Void {
WatchUi.requestUpdate();
}
}
function getApp() as wfApp {
return Application.getApp() as wfApp;
}

22
source/wfBackground.mc Normal file
View File

@ -0,0 +1,22 @@
import Toybox.Application;
import Toybox.Graphics;
import Toybox.Lang;
import Toybox.WatchUi;
class Background extends WatchUi.Drawable {
function initialize() {
var dictionary = {
:identifier => "Background"
};
Drawable.initialize(dictionary);
}
function draw(dc as Dc) as Void {
// Set the background color then call to clear the screen
dc.setColor(Graphics.COLOR_TRANSPARENT, getApp().getProperty("BackgroundColor") as Number);
dc.clear();
}
}

74
source/wfView.mc Normal file
View File

@ -0,0 +1,74 @@
import Toybox.Application;
import Toybox.Graphics;
import Toybox.Lang;
import Toybox.System;
import Toybox.WatchUi;
class wfView extends WatchUi.WatchFace {
private var hands as Hands;
function initialize() {
WatchFace.initialize();
hands = new SimpleHands({});
}
// Load your resources here
function onLayout(dc as Dc) as Void {
setLayout(Rez.Layouts.WatchFace(dc));
}
// 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() as Void {
}
// Update the view
// function onUpdate(dc as Dc) as Void {
// // Get the current time and format it correctly
// var timeFormat = "$1$:$2$";
// var clockTime = System.getClockTime();
// var hours = clockTime.hour;
// if (!System.getDeviceSettings().is24Hour) {
// if (hours > 12) {
// hours = hours - 12;
// }
// } else {
// if (Application.Properties.getValue("UseMilitaryFormat")) {
// timeFormat = "$1$$2$";
// hours = hours.format("%02d");
// }
// }
// var timeString = Lang.format(timeFormat, [hours, clockTime.min.format("%02d")]);
// // Update the view
// var view = View.findDrawableById("TimeLabel") as Text;
// view.setColor(Application.Properties.getValue("ForegroundColor") as Number);
// view.setText(timeString);
// // Call the parent onUpdate function to redraw the layout
// View.onUpdate(dc);
// }
function onUpdate(dc as Dc) as Void {
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
dc.clear();
hands.draw(dc);
}
// Called when this View is removed from the screen. Save the
// state of this View here. This includes freeing resources from
// memory.
function onHide() as Void {
}
// The user has just looked at their watch. Timers and animations may be started here.
function onExitSleep() as Void {
}
// Terminate any active timers and prepare for slow updates.
function onEnterSleep() as Void {
}
}