Quick and dirty widget/glance implementation

This commit is contained in:
SomeoneOnEarth
2023-12-01 15:36:05 +01:00
parent 8c5aa820ef
commit 79b3bc6c21
3 changed files with 217 additions and 220 deletions

View File

@ -11,17 +11,17 @@
P A Abbey & J D Abbey, 31 October 2023 P A Abbey & J D Abbey, 31 October 2023
Widget/Glance App id="bf69be91-5833-4d96-92ea-c5f1a9db5dcc"
Test Application id="98c36259-498a-4458-9cef-74a273ad2bc3" Test Application id="98c36259-498a-4458-9cef-74a273ad2bc3"
Live Application id="40131e87-31ff-454b-a8e2-92276ee399d6" Live Application id="40131e87-31ff-454b-a8e2-92276ee399d6"
--> -->
<iq:manifest version="3" xmlns:iq="http://www.garmin.com/xml/connectiq"> <iq:manifest version="3" xmlns:iq="http://www.garmin.com/xml/connectiq">
<!-- <!--
Use "Monkey C: Edit Application" from the Visual Studio Code command palette Use "Monkey C: Edit Application" from the Visual Studio Code command palette
to update the application attributes. to update the application attributes.
--> -->
<iq:application id="98c36259-498a-4458-9cef-74a273ad2bc3" type="watch-app" name="@Strings.AppName" entry="HomeAssistantApp" launcherIcon="@Drawables.LauncherIcon" minApiLevel="3.1.0"> <iq:application id="bf69be91-5833-4d96-92ea-c5f1a9db5dcc" type="widget" name="@Strings.AppName" entry="HomeAssistantApp" launcherIcon="@Drawables.LauncherIcon" minApiLevel="3.1.0">
<!-- <!--
Use the following from the Visual Studio Code comand palette to edit Use the following from the Visual Studio Code comand palette to edit
the build targets: the build targets:
@ -30,110 +30,63 @@
"Monkey C: Edit Products" - Lets you add or remove any product "Monkey C: Edit Products" - Lets you add or remove any product
--> -->
<iq:products> <iq:products>
<!--
Device Information & References:
* https://developer.garmin.com/connect-iq/compatible-devices/
* https://developer.garmin.com/connect-iq/reference-guides/devices-reference/
-->
<!-- Screen Size 390x390 launcher icon size 70x70 -->
<iq:product id="approachs7042mm"/> <iq:product id="approachs7042mm"/>
<!-- Screen Size 454x454 launcher icon size 80x80 -->
<iq:product id="approachs7047mm"/> <iq:product id="approachs7047mm"/>
<!-- Screen Size 176x176 launcher icon size 62x62 -->
<iq:product id="descentg1"/> <iq:product id="descentg1"/>
<!-- Screen Size 280x280 launcher icon size 40x40 -->
<iq:product id="descentmk2"/> <iq:product id="descentmk2"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="descentmk2s"/> <iq:product id="descentmk2s"/>
<!-- Screen Size 416x416 launcher icon size 70x70 -->
<iq:product id="d2airx10"/> <iq:product id="d2airx10"/>
<!-- Screen Size 416x416 launcher icon size 60x60 -->
<iq:product id="d2mach1"/> <iq:product id="d2mach1"/>
<!-- Screen Size 282x470 launcher icon size 36x36 -->
<iq:product id="edge1030"/> <iq:product id="edge1030"/>
<iq:product id="edge1030bontrager"/> <iq:product id="edge1030bontrager"/>
<iq:product id="edge1030plus"/> <iq:product id="edge1030plus"/>
<!-- Screen Size 282x470 launcher icon size 40x40 -->
<iq:product id="edge1040"/> <iq:product id="edge1040"/>
<!-- Screen Size 246x322 launcher icon size 35x35 -->
<iq:product id="edge530"/> <iq:product id="edge530"/>
<iq:product id="edge830"/> <iq:product id="edge830"/>
<!-- Screen Size 240x400 launcher icon size 36x36 -->
<iq:product id="edgeexplore2"/> <iq:product id="edgeexplore2"/>
<!-- Screen Size 280x280 launcher icon size 40x40 -->
<iq:product id="enduro"/> <iq:product id="enduro"/>
<!-- Screen Size 416x416 launcher icon size 60x60 -->
<iq:product id="epix2"/> <iq:product id="epix2"/>
<!-- Screen Size 390x390 launcher icon size 60x60 -->
<iq:product id="epix2pro42mm"/> <iq:product id="epix2pro42mm"/>
<iq:product id="epix2pro47mm"/> <iq:product id="epix2pro47mm"/>
<!-- Screen Size 454x454 launcher icon size 60x60 -->
<iq:product id="epix2pro51mm"/> <iq:product id="epix2pro51mm"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="fenix5plus"/> <iq:product id="fenix5plus"/>
<iq:product id="fenix5splus"/> <iq:product id="fenix5splus"/>
<iq:product id="fenix5xplus"/> <iq:product id="fenix5xplus"/>
<!-- Screen Size 260x260 launcher icon size 40x40 -->
<iq:product id="fenix6"/> <iq:product id="fenix6"/>
<iq:product id="fenix6pro"/> <iq:product id="fenix6pro"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="fenix6s"/> <iq:product id="fenix6s"/>
<iq:product id="fenix6spro"/> <iq:product id="fenix6spro"/>
<!-- Screen Size 280x280 launcher icon size 40x40 -->
<iq:product id="fenix6xpro"/> <iq:product id="fenix6xpro"/>
<!-- Screen Size 260x260 launcher icon size 40x40 -->
<iq:product id="fenix7"/> <iq:product id="fenix7"/>
<!-- Screen Size 260x260 launcher icon size 40x40 -->
<iq:product id="fenix7pro"/> <iq:product id="fenix7pro"/>
<iq:product id="fenix7pronowifi"/> <iq:product id="fenix7pronowifi"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="fenix7s"/> <iq:product id="fenix7s"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="fenix7spro"/> <iq:product id="fenix7spro"/>
<!-- Screen Size 280x280 launcher icon size 40x40 -->
<iq:product id="fenix7x"/> <iq:product id="fenix7x"/>
<!-- Screen Size 280x280 launcher icon size 40x40 -->
<iq:product id="fenix7xpro"/> <iq:product id="fenix7xpro"/>
<iq:product id="fenix7xpronowifi"/> <iq:product id="fenix7xpronowifi"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="fr245"/> <iq:product id="fr245"/>
<iq:product id="fr245m"/> <iq:product id="fr245m"/>
<!-- Screen Size 260x260 launcher icon size 40x40 -->
<iq:product id="fr255"/> <iq:product id="fr255"/>
<iq:product id="fr255m"/> <iq:product id="fr255m"/>
<!-- Screen Size 218x218 launcher icon size 40x40 -->
<iq:product id="fr255s"/> <iq:product id="fr255s"/>
<iq:product id="fr255sm"/> <iq:product id="fr255sm"/>
<!-- Screen Size 416x416 launcher icon size 60x60 -->
<iq:product id="fr265"/> <iq:product id="fr265"/>
<iq:product id="fr265s"/> <iq:product id="fr265s"/>
<!-- Screen Size 208x208 launcher icon size 35x35 -->
<iq:product id="fr55"/> <iq:product id="fr55"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="fr745"/> <iq:product id="fr745"/>
<iq:product id="fr945"/> <iq:product id="fr945"/>
<iq:product id="fr945lte"/> <iq:product id="fr945lte"/>
<!-- Screen Size 260x260 launcher icon size 40x40 -->
<iq:product id="fr955"/> <iq:product id="fr955"/>
<!-- Screen Size 454x454 launcher icon size 65x65 -->
<iq:product id="fr965"/> <iq:product id="fr965"/>
<!-- Screen Size 176x176 launcher icon size 62x62 -->
<iq:product id="instinct2"/> <iq:product id="instinct2"/>
<!-- Screen Size 163x156 launcher icon size 54x54 -->
<iq:product id="instinct2s"/> <iq:product id="instinct2s"/>
<!-- Screen Size 176x176 launcher icon size 62x62 -->
<iq:product id="instinct2x"/> <iq:product id="instinct2x"/>
<!-- Screen Size 176x176 launcher icon size 26x26 -->
<iq:product id="instinctcrossover"/> <iq:product id="instinctcrossover"/>
<!-- Screen Size 218x218 launcher icon size 30x30 -->
<iq:product id="legacyherocaptainmarvel"/> <iq:product id="legacyherocaptainmarvel"/>
<!-- Screen Size 260x260 launcher icon size 35x35 -->
<iq:product id="legacyherofirstavenger"/> <iq:product id="legacyherofirstavenger"/>
<iq:product id="legacysagadarthvader"/> <iq:product id="legacysagadarthvader"/>
<!-- Screen Size 218x218 launcher icon size 30x30 -->
<iq:product id="legacysagarey"/> <iq:product id="legacysagarey"/>
<!-- Screen Size 240x240 launcher icon size 40x40 -->
<iq:product id="marqadventurer"/> <iq:product id="marqadventurer"/>
<iq:product id="marqathlete"/> <iq:product id="marqathlete"/>
<iq:product id="marqaviator"/> <iq:product id="marqaviator"/>
@ -142,31 +95,20 @@
<iq:product id="marqdriver"/> <iq:product id="marqdriver"/>
<iq:product id="marqexpedition"/> <iq:product id="marqexpedition"/>
<iq:product id="marqgolfer"/> <iq:product id="marqgolfer"/>
<!-- Screen Size 390x390 launcher icon size 60x60 -->
<iq:product id="marq2"/> <iq:product id="marq2"/>
<iq:product id="marq2aviator"/> <iq:product id="marq2aviator"/>
<!-- Screen Size 390x390 launcher icon size 60x60 -->
<iq:product id="venu"/> <iq:product id="venu"/>
<!-- Screen Size 416x416 launcher icon size 70x70 -->
<iq:product id="venu2"/> <iq:product id="venu2"/>
<iq:product id="venu2plus"/> <iq:product id="venu2plus"/>
<!-- Screen Size 360x360 launcher icon size 61x61 -->
<iq:product id="venu2s"/> <iq:product id="venu2s"/>
<!-- Screen Size 240x240 launcher icon size 36x36 -->
<iq:product id="venusq"/> <iq:product id="venusq"/>
<iq:product id="venusqm"/> <iq:product id="venusqm"/>
<!-- Screen Size 320x360 launcher icon size 40x40 -->
<iq:product id="venusq2"/> <iq:product id="venusq2"/>
<iq:product id="venusq2m"/> <iq:product id="venusq2m"/>
<!-- Screen Size 454x454 launcher icon size 70x70 -->
<iq:product id="venu3"/> <iq:product id="venu3"/>
<!-- Screen Size 390x390 launcher icon size 70x70 -->
<iq:product id="venu3s"/> <iq:product id="venu3s"/>
<!-- Screen Size 260x260 launcher icon size 35x35 -->
<iq:product id="vivoactive4"/> <iq:product id="vivoactive4"/>
<!-- Screen Size 218x218 launcher icon size 30x30 -->
<iq:product id="vivoactive4s"/> <iq:product id="vivoactive4s"/>
<!-- Screen Size 390x390 launcher icon size 70x70 -->
<iq:product id="vivoactive5"/> <iq:product id="vivoactive5"/>
</iq:products> </iq:products>
<!-- <!--
@ -210,7 +152,6 @@
<iq:language>por</iq:language> <iq:language>por</iq:language>
<iq:language>slo</iq:language> <iq:language>slo</iq:language>
<iq:language>ron</iq:language> <iq:language>ron</iq:language>
<!-- <iq:language>rus</iq:language> -->
<iq:language>slv</iq:language> <iq:language>slv</iq:language>
<iq:language>spa</iq:language> <iq:language>spa</iq:language>
<iq:language>swe</iq:language> <iq:language>swe</iq:language>

View File

@ -24,24 +24,37 @@ using Toybox.WatchUi;
using Toybox.Application.Properties; using Toybox.Application.Properties;
class HomeAssistantApp extends Application.AppBase { class HomeAssistantApp extends Application.AppBase {
private var mHaMenu; private var mHaMenu as HomeAssistantView or Null;
private var quitTimer as QuitTimer; private var quitTimer as QuitTimer or Null;
private var strNoApiKey as Lang.String; private var strNoApiKey as Lang.String or Null;
private var strNoApiUrl as Lang.String; private var strNoApiUrl as Lang.String or Null;
private var strNoConfigUrl as Lang.String; private var strNoConfigUrl as Lang.String or Null;
private var strNoPhone as Lang.String; private var strNoPhone as Lang.String or Null;
private var strNoInternet as Lang.String; private var strNoInternet as Lang.String or Null;
private var strNoResponse as Lang.String; private var strNoResponse as Lang.String or Null;
private var strNoMenu as Lang.String; private var strNoMenu as Lang.String or Null;
private var strApiFlood as Lang.String; private var strApiFlood as Lang.String or Null;
private var strConfigUrlNotFound as Lang.String; private var strConfigUrlNotFound as Lang.String or Null;
private var strUnhandledHttpErr as Lang.String; private var strUnhandledHttpErr as Lang.String or Null;
private var strTrailingSlashErr as Lang.String; private var strTrailingSlashErr as Lang.String or Null;
private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig() private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
private var mNextItemToUpdate = 0; // Index into the above array private var mNextItemToUpdate = 0; // Index into the above array
function initialize() { function initialize() {
AppBase.initialize(); AppBase.initialize();
}
// onStart() is called on application start up
function onStart(state as Lang.Dictionary?) as Void {
}
// onStop() is called when your application is exiting
function onStop(state as Lang.Dictionary?) as Void {
}
// Return the initial view of your application here
function getInitialView() as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>? {
strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey); strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey);
strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl); strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl);
strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl); strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl);
@ -54,20 +67,7 @@ class HomeAssistantApp extends Application.AppBase {
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr); strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr); strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr);
quitTimer = new QuitTimer(); quitTimer = new QuitTimer();
}
// onStart() is called on application start up
function onStart(state as Lang.Dictionary?) as Void {
quitTimer.begin();
}
// onStop() is called when your application is exiting
function onStop(state as Lang.Dictionary?) as Void {
quitTimer.stop();
}
// Return the initial view of your application here
function getInitialView() as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>? {
var api_url = Properties.getValue("api_url") as Lang.String; var api_url = Properties.getValue("api_url") as Lang.String;
if ((Properties.getValue("api_key") as Lang.String).length() == 0) { if ((Properties.getValue("api_key") as Lang.String).length() == 0) {
@ -100,6 +100,11 @@ class HomeAssistantApp extends Application.AppBase {
System.println("HomeAssistantApp fetchMenuConfig(): No Internet connection, skipping API call."); System.println("HomeAssistantApp fetchMenuConfig(): No Internet connection, skipping API call.");
} }
return [new ErrorView(strNoInternet + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>; return [new ErrorView(strNoInternet + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
}else if (mHaMenu != null ){
// App.getApp().launchInitialView();
return [mHaMenu, new WatchUi.BehaviorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
// return mHaMenu.View;
// WatchUi.pushView(mHaMenu, new HomeAssistantViewDelegate(), WatchUi.SLIDE_IMMEDIATE);
} else { } else {
fetchMenuConfig(); fetchMenuConfig();
return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>; return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
@ -138,7 +143,8 @@ class HomeAssistantApp extends Application.AppBase {
WatchUi.pushView(new ErrorView(strConfigUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP); WatchUi.pushView(new ErrorView(strConfigUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP);
} else if (responseCode == 200) { } else if (responseCode == 200) {
mHaMenu = new HomeAssistantView(data, null); mHaMenu = new HomeAssistantView(data, null);
WatchUi.switchToView(mHaMenu, new HomeAssistantViewDelegate(), WatchUi.SLIDE_IMMEDIATE); quitTimer.begin();
WatchUi.pushView(mHaMenu, new HomeAssistantViewDelegate(), WatchUi.SLIDE_IMMEDIATE);
mItemsToUpdate = mHaMenu.getItemsToUpdate(); mItemsToUpdate = mHaMenu.getItemsToUpdate();
// Start the continuous update process that continues for as long as the application is running. // Start the continuous update process that continues for as long as the application is running.
// The chain of functions from 'updateNextMenuItem()' calls 'updateNextMenuItem()' on completion. // The chain of functions from 'updateNextMenuItem()' calls 'updateNextMenuItem()' on completion.
@ -183,6 +189,10 @@ class HomeAssistantApp extends Application.AppBase {
return quitTimer; return quitTimer;
} }
(:glance)
function getGlanceView() {
return [new HomeAssistantGlanceView()];
}
} }
function getApp() as HomeAssistantApp { function getApp() as HomeAssistantApp {

View File

@ -0,0 +1,46 @@
//-----------------------------------------------------------------------------------
//
// Distributed under MIT Licence
// See https://github.com/house-of-abbey/GarminHomeAssistant/blob/main/LICENSE.
//
//-----------------------------------------------------------------------------------
//
// GarminHomeAssistant is a Garmin IQ application written in Monkey C and routinely
// tested on a Venu 2 device. The source code is provided at:
// https://github.com/house-of-abbey/GarminHomeAssistant.
//
// P A Abbey & J D Abbey & SomeoneOnEarth, 23 November 2023
//
//
// Description:
//
// Application root for GarminHomeAssistant
//
//-----------------------------------------------------------------------------------
import Toybox.WatchUi;
import Toybox.Graphics;
(:glance)
class HomeAssistantGlanceView extends WatchUi.GlanceView {
function initialize() {
GlanceView.initialize();
}
function onShow() {
}
function onHide() {
}
function onUpdate(dc) {
GlanceView.onUpdate(dc);
var font = Graphics.FONT_TINY;
var text = "GarminHomeAssistant";
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
dc.drawText(0, dc.getHeight() / 2, font, text, Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER);
}
}