mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-09-17 22:11:33 +00:00
New glance and widget views
Added ability to test if we're a widget or a watch-app. Added troubleshooting documentation.
This commit is contained in:
@@ -106,10 +106,21 @@ class ErrorView extends ScalableView {
|
||||
create(text); // Ignore returned values
|
||||
if (!mShown) {
|
||||
WatchUi.pushView(instance, instance.getDelegate(), WatchUi.SLIDE_UP);
|
||||
// This must be last to avoid a race condition with unShow(), where the
|
||||
// ErrorView can't be dismissed.
|
||||
mShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
static function unShow() as Void {
|
||||
if (mShown) {
|
||||
WatchUi.popView(WatchUi.SLIDE_DOWN);
|
||||
// This must be last to avoid a race condition with show(), where the
|
||||
// ErrorView can't be dismissed.
|
||||
mShown = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Internal show now we're not a static method like 'show()'.
|
||||
function setText(text as Lang.String) as Void {
|
||||
mText = text;
|
||||
@@ -119,13 +130,6 @@ class ErrorView extends ScalableView {
|
||||
}
|
||||
}
|
||||
|
||||
static function unShow() as Void {
|
||||
if (mShown) {
|
||||
mShown = false;
|
||||
WatchUi.popView(WatchUi.SLIDE_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ErrorDelegate extends WatchUi.BehaviorDelegate {
|
||||
|
@@ -26,4 +26,5 @@ class Globals {
|
||||
static const scDebug = false;
|
||||
static const scAlertTimeout = 2000; // ms
|
||||
static const scTapTimeout = 1000; // ms
|
||||
static const scApiBackoff = 1000; // ms
|
||||
}
|
||||
|
@@ -24,31 +24,38 @@ using Toybox.WatchUi;
|
||||
using Toybox.Application.Properties;
|
||||
|
||||
class HomeAssistantApp extends Application.AppBase {
|
||||
private var mHaMenu as HomeAssistantView or Null;
|
||||
private var mQuitTimer as QuitTimer or Null;
|
||||
private var strNoApiKey as Lang.String or Null;
|
||||
private var strNoApiUrl as Lang.String or Null;
|
||||
private var strNoConfigUrl as Lang.String or Null;
|
||||
private var strNoPhone as Lang.String or Null;
|
||||
private var strNoInternet as Lang.String or Null;
|
||||
private var strNoResponse as Lang.String or Null;
|
||||
private var strNoMenu as Lang.String or Null;
|
||||
private var strApiFlood as Lang.String or Null;
|
||||
private var strConfigUrlNotFound as Lang.String or Null;
|
||||
private var strNoJson as Lang.String or Null;
|
||||
private var strUnhandledHttpErr as Lang.String or Null;
|
||||
private var strTrailingSlashErr as Lang.String or Null;
|
||||
private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
|
||||
private var mNextItemToUpdate = 0; // Index into the above array
|
||||
private var strAvailable = WatchUi.loadResource($.Rez.Strings.Available);
|
||||
private var strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable);
|
||||
|
||||
private var mApiKey as Lang.String;
|
||||
private var mApiStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
private var mMenuStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
private var mHaMenu as HomeAssistantView or Null;
|
||||
private var mQuitTimer as QuitTimer or Null;
|
||||
private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
|
||||
private var mNextItemToUpdate = 0; // Index into the above array
|
||||
private var mIsGlance as Lang.Boolean = false;
|
||||
|
||||
function initialize() {
|
||||
AppBase.initialize();
|
||||
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
// ATTENTION when adding stuff into this block:
|
||||
// Because of the >>GlanceView<<, it should contain only
|
||||
// code, which is used as well for the glance:
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/glances/
|
||||
//
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// "Resource Scopes":
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/resources/
|
||||
//
|
||||
@@ -58,12 +65,13 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
// onStart() is called on application start up
|
||||
function onStart(state as Lang.Dictionary?) as Void {
|
||||
AppBase.onStart(state);
|
||||
// ATTENTION when adding stuff into this block:
|
||||
// Because of the >>GlanceView<<, it should contain only
|
||||
// code, which is used as well for the glance:
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/glances/
|
||||
//
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// "Resource Scopes":
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/resources/
|
||||
//
|
||||
@@ -73,12 +81,13 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
// onStop() is called when your application is exiting
|
||||
function onStop(state as Lang.Dictionary?) as Void {
|
||||
AppBase.onStop(state);
|
||||
// ATTENTION when adding stuff into this block:
|
||||
// Because of the >>GlanceView<<, it should contain only
|
||||
// code, which is used as well for the glance:
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/glances/
|
||||
//
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// "Resource Scopes":
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/resources/
|
||||
//
|
||||
@@ -88,16 +97,15 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
// Return the initial view of your application here
|
||||
function getInitialView() as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>? {
|
||||
|
||||
strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey);
|
||||
strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl);
|
||||
strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl);
|
||||
strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||
strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu);
|
||||
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||
strConfigUrlNotFound = WatchUi.loadResource($.Rez.Strings.ConfigUrlNotFound);
|
||||
strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson);
|
||||
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr);
|
||||
mQuitTimer = new QuitTimer();
|
||||
@@ -136,61 +144,102 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
return ErrorView.create(strNoInternet + ".");
|
||||
} else {
|
||||
fetchMenuConfig();
|
||||
return [new RootView(self), new RootViewDelegate(self)] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
fetchApiStatus();
|
||||
if (WidgetApp.isWidget) {
|
||||
return [new RootView(self), new RootViewDelegate(self)] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
} else {
|
||||
return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Callback function after completing the GET request to fetch the configuration menu.
|
||||
//
|
||||
(:glance)
|
||||
function onReturnFetchMenuConfig(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: " + responseCode);
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Data: " + data);
|
||||
}
|
||||
if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
} else if (responseCode == Communications.BLE_QUEUE_FULL) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
// Don't need to worry about multiple ErrorViews here as the fetch does not happen a second time.
|
||||
ErrorView.show(strApiFlood);
|
||||
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
ErrorView.show(strNoResponse);
|
||||
} else if (responseCode == 404) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting.");
|
||||
}
|
||||
ErrorView.show(strConfigUrlNotFound);
|
||||
} else if (responseCode == 200) {
|
||||
mHaMenu = new HomeAssistantView(data, null);
|
||||
mQuitTimer.begin();
|
||||
pushHomeAssistantMenuView();
|
||||
mItemsToUpdate = mHaMenu.getItemsToUpdate();
|
||||
// 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.
|
||||
if (mItemsToUpdate.size() > 0) {
|
||||
updateNextMenuItem();
|
||||
}
|
||||
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Network request timeout.");
|
||||
}
|
||||
ErrorView.show(strNoMenu + ". " + strNoInternet + "?");
|
||||
} else {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode );
|
||||
|
||||
mMenuStatus = strUnavailable;
|
||||
switch (responseCode) {
|
||||
case Communications.BLE_HOST_TIMEOUT:
|
||||
case Communications.BLE_CONNECTION_UNAVAILABLE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.BLE_QUEUE_FULL:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strApiFlood);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoResponse);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoJson);
|
||||
}
|
||||
break;
|
||||
|
||||
case 404:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strConfigUrlNotFound);
|
||||
}
|
||||
break;
|
||||
|
||||
case 200:
|
||||
mMenuStatus = strAvailable;
|
||||
if (!mIsGlance) {
|
||||
mHaMenu = new HomeAssistantView(data, null);
|
||||
mQuitTimer.begin();
|
||||
mItemsToUpdate = mHaMenu.getItemsToUpdate();
|
||||
// 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.
|
||||
if (mItemsToUpdate.size() > 0) {
|
||||
updateNextMenuItem();
|
||||
}
|
||||
if (!WidgetApp.isWidget) {
|
||||
WatchUi.switchToView(mHaMenu, new HomeAssistantViewDelegate(false), WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
}
|
||||
WatchUi.requestUpdate();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function fetchMenuConfig() as Void {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
@@ -204,11 +253,120 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
);
|
||||
}
|
||||
|
||||
function homeAssistantMenuIsLoaded() as Lang.Boolean{
|
||||
return mHaMenu!=null;
|
||||
// Callback function after completing the GET request to fetch the API status.
|
||||
//
|
||||
(:glance)
|
||||
function onReturnFetchApiStatus(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: " + responseCode);
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Data: " + data);
|
||||
}
|
||||
|
||||
mApiStatus = strUnavailable;
|
||||
switch (responseCode) {
|
||||
case Communications.BLE_HOST_TIMEOUT:
|
||||
case Communications.BLE_CONNECTION_UNAVAILABLE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.BLE_QUEUE_FULL:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strApiFlood);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoResponse);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoJson);
|
||||
}
|
||||
break;
|
||||
|
||||
case 404:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: 404, page not found. Check Configuration URL setting.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strConfigUrlNotFound);
|
||||
}
|
||||
break;
|
||||
|
||||
case 200:
|
||||
var msg = null;
|
||||
if (data != null) {
|
||||
msg = data.get("message");
|
||||
}
|
||||
if (msg.equals("API running.")) {
|
||||
mApiStatus = strAvailable;
|
||||
} else {
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show("API " + mApiStatus + ".");
|
||||
}
|
||||
}
|
||||
WatchUi.requestUpdate();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pushHomeAssistantMenuView() as Void{
|
||||
(:glance)
|
||||
function fetchApiStatus() as Void {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Authorization" => "Bearer " + mApiKey
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
};
|
||||
Communications.makeWebRequest(
|
||||
Properties.getValue("api_url") + "/",
|
||||
null,
|
||||
options,
|
||||
method(:onReturnFetchApiStatus)
|
||||
);
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function getApiStatus() as Lang.String {
|
||||
return mApiStatus;
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function getMenuStatus() as Lang.String {
|
||||
return mMenuStatus;
|
||||
}
|
||||
|
||||
function isHomeAssistantMenuLoaded() as Lang.Boolean {
|
||||
return mHaMenu != null;
|
||||
}
|
||||
|
||||
function pushHomeAssistantMenuView() as Void {
|
||||
WatchUi.pushView(mHaMenu, new HomeAssistantViewDelegate(true), WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
|
||||
@@ -220,13 +378,16 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
mNextItemToUpdate = (mNextItemToUpdate + 1) % itu.size();
|
||||
}
|
||||
|
||||
function getQuitTimer() as QuitTimer{
|
||||
function getQuitTimer() as QuitTimer {
|
||||
return mQuitTimer;
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function getGlanceView() {
|
||||
return [new HomeAssistantGlanceView()];
|
||||
mIsGlance = true;
|
||||
fetchMenuConfig();
|
||||
fetchApiStatus();
|
||||
return [new HomeAssistantGlanceView(self)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -24,19 +24,86 @@ using Toybox.Graphics;
|
||||
|
||||
(:glance)
|
||||
class HomeAssistantGlanceView extends WatchUi.GlanceView {
|
||||
private static const scLeftMargin = 20; // in pixels
|
||||
private static const scLeftIndent = 10; // Left Indent "_text:" in pixels
|
||||
private static const scMidSep = 10; // Middle Separator "text:_text" in pixels
|
||||
private var mApp as HomeAssistantApp;
|
||||
private var mTitle as WatchUi.Text or Null;
|
||||
private var mApiText as WatchUi.Text or Null;
|
||||
private var mApiStatus as WatchUi.Text or Null;
|
||||
private var mMenuText as WatchUi.Text or Null;
|
||||
private var mMenuStatus as WatchUi.Text or Null;
|
||||
|
||||
private var mText as Lang.String;
|
||||
|
||||
function initialize() {
|
||||
function initialize(app as HomeAssistantApp) {
|
||||
GlanceView.initialize();
|
||||
mApp = app;
|
||||
}
|
||||
|
||||
mText = WatchUi.loadResource($.Rez.Strings.AppName);
|
||||
function onLayout(dc as Graphics.Dc) as Void {
|
||||
var strChecking = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
var strGlanceMenu = WatchUi.loadResource($.Rez.Strings.GlanceMenu);
|
||||
var h = dc.getHeight();
|
||||
var tw = dc.getTextWidthInPixels(strGlanceMenu, Graphics.FONT_XTINY);
|
||||
|
||||
mTitle = new WatchUi.Text({
|
||||
:text => WatchUi.loadResource($.Rez.Strings.AppName),
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_TINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin,
|
||||
:locY => 1 * h / 6
|
||||
});
|
||||
|
||||
mApiText = new WatchUi.Text({
|
||||
:text => "API:",
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + tw,
|
||||
:locY => 3 * h / 6
|
||||
});
|
||||
mApiStatus = new WatchUi.Text({
|
||||
:text => strChecking,
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + scMidSep + tw,
|
||||
:locY => 3 * h / 6
|
||||
});
|
||||
mMenuText = new WatchUi.Text({
|
||||
:text => strGlanceMenu + ":",
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + tw,
|
||||
:locY => 5 * h / 6
|
||||
});
|
||||
mMenuStatus = new WatchUi.Text({
|
||||
:text => strChecking,
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + scMidSep + tw,
|
||||
:locY => 5 * h / 6
|
||||
});
|
||||
}
|
||||
|
||||
function onUpdate(dc) as Void {
|
||||
GlanceView.onUpdate(dc);
|
||||
|
||||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
|
||||
dc.drawText(0, dc.getHeight() / 2, Graphics.FONT_TINY, mText, Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
if(dc has :setAntiAlias) {
|
||||
dc.setAntiAlias(true);
|
||||
}
|
||||
dc.setColor(
|
||||
Graphics.COLOR_WHITE,
|
||||
Graphics.COLOR_BLUE
|
||||
);
|
||||
dc.clear();
|
||||
mTitle.draw(dc);
|
||||
mApiText.draw(dc);
|
||||
mApiStatus.setText(mApp.getApiStatus());
|
||||
mApiStatus.draw(dc);
|
||||
mMenuText.draw(dc);
|
||||
mMenuStatus.setText(mApp.getMenuStatus());
|
||||
mMenuStatus.draw(dc);
|
||||
}
|
||||
}
|
||||
|
@@ -24,22 +24,18 @@ using Toybox.Graphics;
|
||||
using Toybox.Application.Properties;
|
||||
|
||||
class HomeAssistantService {
|
||||
private var mApiKey as Lang.String;
|
||||
private var strNoPhone as Lang.String;
|
||||
private var strNoInternet as Lang.String;
|
||||
private var strNoResponse as Lang.String;
|
||||
private var strApiFlood as Lang.String;
|
||||
private var strApiUrlNotFound as Lang.String;
|
||||
private var strUnhandledHttpErr as Lang.String;
|
||||
private var strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||
private var strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
private var strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||
private var strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson);
|
||||
private var strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||
private var strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
||||
private var strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
|
||||
private var mApiKey as Lang.String;
|
||||
|
||||
function initialize() {
|
||||
strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||
strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
||||
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
}
|
||||
|
||||
// Callback function after completing the POST request to call a service.
|
||||
@@ -50,54 +46,79 @@ class HomeAssistantService {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: " + responseCode);
|
||||
System.println("HomeAssistantService onReturnCall() Response Data: " + data);
|
||||
}
|
||||
if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
} else if (responseCode == Communications.BLE_QUEUE_FULL) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
// Don't need to worry about multiple ErrorViews here as the call is not on a repeat timer.
|
||||
ErrorView.show(strApiFlood);
|
||||
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
ErrorView.show(strNoResponse);
|
||||
} else if (responseCode == 404) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: 404, page not found. Check API URL setting.");
|
||||
}
|
||||
ErrorView.show(strApiUrlNotFound);
|
||||
} else if (responseCode == 200) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall(): Service executed.");
|
||||
}
|
||||
var d = data as Lang.Array;
|
||||
var toast = "Executed";
|
||||
for(var i = 0; i < d.size(); i++) {
|
||||
if ((d[i].get("entity_id") as Lang.String).equals(identifier)) {
|
||||
toast = (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String;
|
||||
|
||||
switch (responseCode) {
|
||||
case Communications.BLE_HOST_TIMEOUT:
|
||||
case Communications.BLE_CONNECTION_UNAVAILABLE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
}
|
||||
if (WatchUi has :showToast) {
|
||||
WatchUi.showToast(toast, null);
|
||||
} else {
|
||||
new Alert({
|
||||
:timeout => Globals.scAlertTimeout,
|
||||
:font => Graphics.FONT_MEDIUM,
|
||||
:text => toast,
|
||||
:fgcolor => Graphics.COLOR_WHITE,
|
||||
:bgcolor => Graphics.COLOR_BLACK
|
||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
} else {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode );
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
break;
|
||||
|
||||
case Communications.BLE_QUEUE_FULL:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
ErrorView.show(strApiFlood);
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
ErrorView.show(strNoResponse);
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_RESPONSE_OUT_OF_MEMORY:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: NETWORK_RESPONSE_OUT_OF_MEMORY, are we going too fast?");
|
||||
}
|
||||
// Ignore and see if we can carry on
|
||||
break;
|
||||
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
|
||||
}
|
||||
ErrorView.show(strNoJson);
|
||||
break;
|
||||
|
||||
case 404:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall() Response Code: 404, page not found. Check API URL setting.");
|
||||
}
|
||||
ErrorView.show(strApiUrlNotFound);
|
||||
break;
|
||||
|
||||
case 200:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall(): Service executed.");
|
||||
}
|
||||
var d = data as Lang.Array;
|
||||
var toast = "Executed";
|
||||
for(var i = 0; i < d.size(); i++) {
|
||||
if ((d[i].get("entity_id") as Lang.String).equals(identifier)) {
|
||||
toast = (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String;
|
||||
}
|
||||
}
|
||||
if (WatchUi has :showToast) {
|
||||
WatchUi.showToast(toast, null);
|
||||
} else {
|
||||
new Alert({
|
||||
:timeout => Globals.scAlertTimeout,
|
||||
:font => Graphics.FONT_MEDIUM,
|
||||
:text => toast,
|
||||
:fgcolor => Graphics.COLOR_WHITE,
|
||||
:bgcolor => Graphics.COLOR_BLACK
|
||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService onReturnCall(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -25,13 +25,15 @@ using Toybox.Application.Properties;
|
||||
using Toybox.Timer;
|
||||
|
||||
class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
private var mApiKey as Lang.String;
|
||||
private var strNoPhone as Lang.String;
|
||||
private var strNoInternet as Lang.String;
|
||||
private var strNoResponse as Lang.String;
|
||||
private var strApiFlood as Lang.String;
|
||||
private var strApiUrlNotFound as Lang.String;
|
||||
private var strUnhandledHttpErr as Lang.String;
|
||||
private var strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||
private var strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
private var strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||
private var strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson);
|
||||
private var strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||
private var strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
||||
private var strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
|
||||
private var mApiKey as Lang.String;
|
||||
|
||||
function initialize(
|
||||
label as Lang.String or Lang.Symbol,
|
||||
@@ -46,13 +48,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
|
||||
} or Null
|
||||
) {
|
||||
strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||
strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
||||
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
WatchUi.ToggleMenuItem.initialize(label, subLabel, identifier, enabled, options);
|
||||
}
|
||||
|
||||
@@ -75,6 +71,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: " + responseCode);
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Data: " + data);
|
||||
}
|
||||
|
||||
// Provide the ability to terminate updating chain of calls for a permanent network error.
|
||||
var keepUpdating = true;
|
||||
switch (responseCode) {
|
||||
@@ -85,29 +82,50 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
}
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
break;
|
||||
|
||||
case Communications.BLE_QUEUE_FULL:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
ErrorView.show(strApiFlood);
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
ErrorView.show(strNoResponse);
|
||||
break;
|
||||
|
||||
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
|
||||
}
|
||||
ErrorView.show(strNoJson);
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_RESPONSE_OUT_OF_MEMORY:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: NETWORK_RESPONSE_OUT_OF_MEMORY, are we going too fast?");
|
||||
}
|
||||
// Pause updates
|
||||
keepUpdating = false;
|
||||
var myTimer = new Timer.Timer();
|
||||
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
|
||||
myTimer.start(getApp().method(:updateNextMenuItem), Globals.scApiBackoff, false);
|
||||
break;
|
||||
|
||||
case 404:
|
||||
var msg = null;
|
||||
if (data != null) {
|
||||
msg = data.get("message");
|
||||
}
|
||||
if (msg != null) {
|
||||
// Should be an HTTP 405 according to curl queries
|
||||
// Should be an HTTP 404 according to curl queries
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 404. " + mIdentifier + " " + msg);
|
||||
}
|
||||
ErrorView.show("HTTP 405, " + mIdentifier + ". " + data.get("message"));
|
||||
ErrorView.show("HTTP 404, " + mIdentifier + ". " + data.get("message"));
|
||||
} else {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 404, page not found. Check API URL setting.");
|
||||
@@ -116,6 +134,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
}
|
||||
keepUpdating = false;
|
||||
break;
|
||||
|
||||
case 405:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 405. " + mIdentifier + " " + data.get("message"));
|
||||
@@ -123,6 +142,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
ErrorView.show("HTTP 405, " + mIdentifier + ". " + data.get("message"));
|
||||
keepUpdating = false;
|
||||
break;
|
||||
|
||||
case 200:
|
||||
var state = data.get("state") as Lang.String;
|
||||
if (Globals.scDebug) {
|
||||
@@ -134,6 +154,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
setUiToggle(state);
|
||||
ErrorView.unShow();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState(): Unhandled HTTP response code = " + responseCode);
|
||||
@@ -199,43 +220,63 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: " + responseCode);
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Data: " + data);
|
||||
}
|
||||
if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
} else if (responseCode == Communications.BLE_QUEUE_FULL) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
ErrorView.show(strApiFlood);
|
||||
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
ErrorView.show(strNoResponse);
|
||||
} else if (responseCode == 404) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: 404, page not found. Check API URL setting.");
|
||||
}
|
||||
ErrorView.show(strApiUrlNotFound);
|
||||
} else if (responseCode == 200) {
|
||||
var state;
|
||||
var d = data as Lang.Array;
|
||||
for(var i = 0; i < d.size(); i++) {
|
||||
if ((d[i].get("entity_id") as Lang.String).equals(mIdentifier)) {
|
||||
state = d[i].get("state") as Lang.String;
|
||||
if (Globals.scDebug) {
|
||||
System.println((d[i].get("attributes") as Lang.Dictionary).get("friendly_name") + " State=" + state);
|
||||
}
|
||||
setUiToggle(state);
|
||||
|
||||
switch (responseCode) {
|
||||
case Communications.BLE_HOST_TIMEOUT:
|
||||
case Communications.BLE_CONNECTION_UNAVAILABLE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode );
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
break;
|
||||
|
||||
case Communications.BLE_QUEUE_FULL:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
ErrorView.show(strApiFlood);
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
ErrorView.show(strNoResponse);
|
||||
break;
|
||||
|
||||
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
|
||||
}
|
||||
ErrorView.show(strNoJson);
|
||||
break;
|
||||
|
||||
case 404:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: 404, page not found. Check API URL setting.");
|
||||
}
|
||||
ErrorView.show(strApiUrlNotFound);
|
||||
break;
|
||||
|
||||
case 200:
|
||||
var state;
|
||||
var d = data as Lang.Array;
|
||||
for(var i = 0; i < d.size(); i++) {
|
||||
if ((d[i].get("entity_id") as Lang.String).equals(mIdentifier)) {
|
||||
state = d[i].get("state") as Lang.String;
|
||||
if (Globals.scDebug) {
|
||||
System.println((d[i].get("attributes") as Lang.Dictionary).get("friendly_name") + " State=" + state);
|
||||
}
|
||||
setUiToggle(state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnSetState(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -103,20 +103,21 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
// Reference: https://developer.garmin.com/connect-iq/core-topics/input-handling/
|
||||
//
|
||||
class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
|
||||
|
||||
private var mIsRootMenuView = false;
|
||||
private var mIsRootMenuView as Lang.Boolean = false;
|
||||
private var mTimer as QuitTimer;
|
||||
|
||||
function initialize(isRootMenuView as Lang.Boolean) {
|
||||
Menu2InputDelegate.initialize();
|
||||
mIsRootMenuView = isRootMenuView;
|
||||
mTimer = getApp().getQuitTimer();
|
||||
}
|
||||
|
||||
function onBack() {
|
||||
getApp().getQuitTimer().reset();
|
||||
mTimer.reset();
|
||||
|
||||
if (mIsRootMenuView){
|
||||
if (mIsRootMenuView) {
|
||||
// If its started from glance or as an activity, directly exit the widget/app
|
||||
// (on widgets without glance, this exit() won`t do anything,
|
||||
// (on widgets without glance, this exit() won't do anything,
|
||||
// so the base view will be shown instead, through the popView below this "if body")
|
||||
System.exit();
|
||||
}
|
||||
@@ -126,16 +127,16 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
|
||||
|
||||
// Only for CheckboxMenu
|
||||
function onDone() {
|
||||
getApp().getQuitTimer().reset();
|
||||
mTimer.reset();
|
||||
}
|
||||
|
||||
// Only for CustomMenu
|
||||
function onFooter() {
|
||||
getApp().getQuitTimer().reset();
|
||||
mTimer.reset();
|
||||
}
|
||||
|
||||
function onSelect(item as WatchUi.MenuItem) as Void {
|
||||
getApp().getQuitTimer().reset();
|
||||
mTimer.reset();
|
||||
if (item instanceof HomeAssistantToggleMenuItem) {
|
||||
var haToggleItem = item as HomeAssistantToggleMenuItem;
|
||||
if (Globals.scDebug) {
|
||||
@@ -175,7 +176,7 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
|
||||
|
||||
// Only for CustomMenu
|
||||
function onTitle() {
|
||||
getApp().getQuitTimer().reset();
|
||||
mTimer.reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,76 +25,99 @@ using Toybox.WatchUi;
|
||||
class RootView extends ScalableView {
|
||||
|
||||
// ATTENTION when the app is running as a "widget" (that means, it runs on devices
|
||||
// without glance view support), the input events in this view are limited, as
|
||||
// without glance view support), the input events in this view are limited, as
|
||||
// described under "Base View and the Widget Carousel" on:
|
||||
//
|
||||
//
|
||||
// https://developer.garmin.com/connect-iq/connect-iq-basics/app-types/
|
||||
//
|
||||
//
|
||||
// Also the view type of the base view is limited too (for example "WatchUi.Menu2"
|
||||
// is not possible)).
|
||||
//
|
||||
// Also System.exit() is not working/do nothing when running as a widget: A widget will be
|
||||
//
|
||||
// Also System.exit() is not working/do nothing when running as a widget: A widget will be
|
||||
// terminated automatically by OS after some time or can be quit manually, when on the base
|
||||
// view a swipe to left / "back button" press is done.
|
||||
|
||||
private var mApp as HomeAssistantApp;
|
||||
private var strFetchingMenuConfig as Lang.String;
|
||||
private var strExit as Lang.String;
|
||||
private var mTextAreaExit as WatchUi.TextArea or Null;
|
||||
private var mTextAreaFetching as WatchUi.TextArea or Null;
|
||||
private static const scMidSep = 10; // Middle Separator "text:_text" in pixels
|
||||
private var mApp as HomeAssistantApp;
|
||||
private var mTitle as WatchUi.Text or Null;
|
||||
private var mApiText as WatchUi.Text or Null;
|
||||
private var mApiStatus as WatchUi.Text or Null;
|
||||
private var mMenuText as WatchUi.Text or Null;
|
||||
private var mMenuStatus as WatchUi.Text or Null;
|
||||
|
||||
function initialize(app as HomeAssistantApp) {
|
||||
ScalableView.initialize();
|
||||
mApp=app;
|
||||
|
||||
strFetchingMenuConfig = WatchUi.loadResource($.Rez.Strings.FetchingMenuConfig);
|
||||
|
||||
if (System.getDeviceSettings().isTouchScreen){
|
||||
strExit = WatchUi.loadResource($.Rez.Strings.ExitViewTouch);
|
||||
} else {
|
||||
strExit = WatchUi.loadResource($.Rez.Strings.ExitViewButtons);
|
||||
}
|
||||
mApp = app;
|
||||
}
|
||||
|
||||
function onLayout(dc as Graphics.Dc) as Void {
|
||||
var w = dc.getWidth();
|
||||
var h = dc.getHeight();
|
||||
var strChecking = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
var w = dc.getWidth();
|
||||
|
||||
mTextAreaExit = new WatchUi.TextArea({
|
||||
:text => strExit,
|
||||
mTitle = new WatchUi.Text({
|
||||
:text => WatchUi.loadResource($.Rez.Strings.AppName),
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:font => Graphics.FONT_TINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => 0,
|
||||
:locY => 83,
|
||||
:width => w,
|
||||
:height => h - 166
|
||||
:locX => w/2,
|
||||
:locY => pixelsForScreen(30.0)
|
||||
});
|
||||
|
||||
mTextAreaFetching = new WatchUi.TextArea({
|
||||
:text => strFetchingMenuConfig,
|
||||
mApiText = new WatchUi.Text({
|
||||
:text => "API:",
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => 0,
|
||||
:locY => 83,
|
||||
:width => w,
|
||||
:height => h - 166
|
||||
:justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => w/2 - scMidSep/2,
|
||||
:locY => pixelsForScreen(50.0)
|
||||
});
|
||||
mApiStatus = new WatchUi.Text({
|
||||
:text => strChecking,
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => w/2 + scMidSep/2,
|
||||
:locY => pixelsForScreen(50.0)
|
||||
});
|
||||
mMenuText = new WatchUi.Text({
|
||||
:text => WatchUi.loadResource($.Rez.Strings.GlanceMenu) + ":",
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => w/2 - scMidSep/2,
|
||||
:locY => pixelsForScreen(70.0)
|
||||
});
|
||||
mMenuStatus = new WatchUi.Text({
|
||||
:text => strChecking,
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => w/2 + scMidSep/2,
|
||||
:locY => pixelsForScreen(70.0)
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function onUpdate(dc as Graphics.Dc) as Void {
|
||||
if(dc has :setAntiAlias) {
|
||||
if (dc has :setAntiAlias) {
|
||||
dc.setAntiAlias(true);
|
||||
}
|
||||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
|
||||
dc.clear();
|
||||
|
||||
if(mApp.homeAssistantMenuIsLoaded()) {
|
||||
mTextAreaExit.draw(dc);
|
||||
} else {
|
||||
mTextAreaFetching.draw(dc);
|
||||
}
|
||||
// Initialise this locally, otherwise the venu1 device runs out of memory when stored at class level.
|
||||
var launcherIcon = Application.loadResource(Rez.Drawables.LauncherIcon);
|
||||
var w = dc.getWidth();
|
||||
var h = dc.getHeight();
|
||||
dc.drawBitmap(w/2 - launcherIcon.getWidth()/2, h/8 - launcherIcon.getHeight()/2, launcherIcon);
|
||||
mTitle.draw(dc);
|
||||
mApiText.draw(dc);
|
||||
mApiStatus.setText(mApp.getApiStatus());
|
||||
mApiStatus.draw(dc);
|
||||
mMenuText.draw(dc);
|
||||
mMenuStatus.setText(mApp.getMenuStatus());
|
||||
mMenuStatus.draw(dc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +125,9 @@ class RootViewDelegate extends WatchUi.BehaviorDelegate {
|
||||
|
||||
var mApp as HomeAssistantApp;
|
||||
|
||||
function initialize(app as HomeAssistantApp ) {
|
||||
function initialize(app as HomeAssistantApp) {
|
||||
BehaviorDelegate.initialize();
|
||||
mApp=app;
|
||||
mApp = app;
|
||||
}
|
||||
|
||||
function onTap(evt as WatchUi.ClickEvent) as Lang.Boolean {
|
||||
@@ -115,12 +138,12 @@ class RootViewDelegate extends WatchUi.BehaviorDelegate {
|
||||
return backToMainMenu();
|
||||
}
|
||||
|
||||
function onMenu() as Lang.Boolean{
|
||||
function onMenu() as Lang.Boolean {
|
||||
return backToMainMenu();
|
||||
}
|
||||
|
||||
private function backToMainMenu() as Lang.Boolean{
|
||||
if(mApp.homeAssistantMenuIsLoaded()){
|
||||
private function backToMainMenu() as Lang.Boolean {
|
||||
if (mApp.isHomeAssistantMenuLoaded()) {
|
||||
mApp.pushHomeAssistantMenuView();
|
||||
return true;
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ class ScalableView extends WatchUi.View {
|
||||
|
||||
function initialize() {
|
||||
View.initialize();
|
||||
mScreenWidth = System.getDeviceSettings().screenWidth;
|
||||
}
|
||||
|
||||
// Convert a fraction expressed as a percentage (%) to a number of pixels for the
|
||||
@@ -40,9 +41,6 @@ class ScalableView extends WatchUi.View {
|
||||
// height > width.
|
||||
//
|
||||
function pixelsForScreen(pc as Lang.Float) as Lang.Number {
|
||||
if (mScreenWidth == null) {
|
||||
mScreenWidth = System.getDeviceSettings().screenWidth;
|
||||
}
|
||||
return Math.round(pc * mScreenWidth) / 100;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user