mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-10-31 23:48:13 +00:00
Added numeric Menu Item
This commit is contained in:
231
source/HomeAssistantNumericMenuItem.mc
Normal file
231
source/HomeAssistantNumericMenuItem.mc
Normal file
@@ -0,0 +1,231 @@
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// 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 & Someone0nEarth, 31 October 2023
|
||||
//
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
using Toybox.Lang;
|
||||
using Toybox.WatchUi;
|
||||
using Toybox.Graphics;
|
||||
|
||||
|
||||
//! Menu button with an icon that opens a sub-menu, i.e. group, and optionally renders
|
||||
//! a Home Assistant Template.
|
||||
//
|
||||
class HomeAssistantNumericMenuItem extends HomeAssistantMenuItem {
|
||||
private var mHomeAssistantService as HomeAssistantService?;
|
||||
private var mService as Lang.String?;
|
||||
private var mConfirm as Lang.Boolean;
|
||||
private var mExit as Lang.Boolean;
|
||||
private var mPin as Lang.Boolean;
|
||||
private var mData as Lang.Dictionary?;
|
||||
private var mStep as Lang.Float=1.0;
|
||||
private var mValueChanged as Lang.Boolean = false;
|
||||
private var mValue as Lang.Float?;
|
||||
private var mEntity as Lang.String?;
|
||||
private var mFormatString as Lang.String="%.1f";
|
||||
|
||||
|
||||
//! Class Constructor
|
||||
//!
|
||||
//! @param label Menu item label.
|
||||
//! @param template Menu item template.
|
||||
//! @param service Menu item service.
|
||||
//! @param data Data to supply to the service call.
|
||||
//! @param exit Should the service call complete and then exit?
|
||||
//! @param confirm Should the service call be confirmed to avoid accidental invocation?
|
||||
//! @param pin Should the service call be protected with a PIN for some low level of security?
|
||||
//! @param icon Icon to use for the menu item.
|
||||
//! @param options Menu item options to be passed on, including both SDK and menu options, e.g. exit, confirm & pin.
|
||||
//! @param haService Shared Home Assistant service object that will perform the required call. Only
|
||||
//! one of these objects is created for all menu items to re-use.
|
||||
//
|
||||
function initialize(
|
||||
label as Lang.String or Lang.Symbol,
|
||||
entity as Lang.String,
|
||||
template as Lang.String,
|
||||
service as Lang.String?,
|
||||
data as Lang.Dictionary?,
|
||||
options as {
|
||||
:alignment as WatchUi.MenuItem.Alignment,
|
||||
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol,
|
||||
:exit as Lang.Boolean,
|
||||
:confirm as Lang.Boolean,
|
||||
:pin as Lang.Boolean
|
||||
}?,
|
||||
haService as HomeAssistantService
|
||||
) {
|
||||
mService = service;
|
||||
mData = data;
|
||||
mExit = options[:exit];
|
||||
mConfirm = options[:confirm];
|
||||
mPin = options[:pin];
|
||||
mLabel = label;
|
||||
mHomeAssistantService = haService;
|
||||
mEntity = entity;
|
||||
|
||||
HomeAssistantMenuItem.initialize(
|
||||
label,
|
||||
template,
|
||||
{
|
||||
:alignment => options[:alignment],
|
||||
:icon => options[:icon]
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
if (mData.get("step") != null) {
|
||||
mStep = mData.get("step").toString().toFloat();
|
||||
}
|
||||
|
||||
if (mData.get("formatString") != null) {
|
||||
mFormatString=mData.get("formatString").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function callService() as Void {
|
||||
if (!mValueChanged) { return; }
|
||||
var hasTouchScreen = System.getDeviceSettings().isTouchScreen;
|
||||
if (mPin && hasTouchScreen) {
|
||||
var pin = Settings.getPin();
|
||||
if (pin != null) {
|
||||
var pinConfirmationView = new HomeAssistantPinConfirmationView();
|
||||
WatchUi.pushView(
|
||||
pinConfirmationView,
|
||||
new HomeAssistantPinConfirmationDelegate({
|
||||
:callback => method(:onConfirm),
|
||||
:pin => pin,
|
||||
:state => false,
|
||||
:view => pinConfirmationView,
|
||||
}),
|
||||
WatchUi.SLIDE_IMMEDIATE
|
||||
);
|
||||
}
|
||||
} else if (mConfirm) {
|
||||
if ((! System.getDeviceSettings().phoneConnected ||
|
||||
! System.getDeviceSettings().connectionAvailable) &&
|
||||
Settings.getWifiLteExecutionEnabled()) {
|
||||
var dialogMsg = WatchUi.loadResource($.Rez.Strings.WifiLtePrompt) as Lang.String;
|
||||
var dialog = new WatchUi.Confirmation(dialogMsg);
|
||||
WatchUi.pushView(
|
||||
dialog,
|
||||
new WifiLteExecutionConfirmDelegate({
|
||||
:type => "service",
|
||||
:service => mService,
|
||||
:data => mData,
|
||||
:exit => mExit,
|
||||
}, dialog),
|
||||
WatchUi.SLIDE_LEFT
|
||||
);
|
||||
} else {
|
||||
var view = new HomeAssistantConfirmation();
|
||||
WatchUi.pushView(
|
||||
view,
|
||||
new HomeAssistantConfirmationDelegate({
|
||||
:callback => method(:onConfirm),
|
||||
:confirmationView => view,
|
||||
:state => false,
|
||||
}),
|
||||
WatchUi.SLIDE_IMMEDIATE
|
||||
);
|
||||
}
|
||||
} else {
|
||||
onConfirm(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! Callback function after the menu items selection has been (optionally) confirmed.
|
||||
//!
|
||||
//! @param b Ignored. It is included in order to match the expected function prototype of the callback method.
|
||||
//
|
||||
function onConfirm(b as Lang.Boolean) as Void {
|
||||
if (mService != null) {
|
||||
mHomeAssistantService.call(mService, {"entity_id" => mEntity,mData.get("valueLabel").toString() => mValue}, mExit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///! Increase value when Up button is pressed or touch screen swipe down
|
||||
|
||||
function increaseValue() as Void {
|
||||
if (mValueChanged)
|
||||
{
|
||||
mValue += mStep;
|
||||
}
|
||||
else {
|
||||
mValue= getSubLabel().toFloat() + mStep;
|
||||
mValueChanged=true;
|
||||
}
|
||||
setSubLabel(mValue.format(mFormatString));
|
||||
}
|
||||
|
||||
///! Decrease value when Down button is pressed or touch screen swipe up
|
||||
function decreaseValue() as Void {
|
||||
if (mValueChanged)
|
||||
{
|
||||
mValue -= mStep;
|
||||
}
|
||||
else {
|
||||
mValue= getSubLabel().toFloat() - mStep;
|
||||
mValueChanged=true;
|
||||
}
|
||||
setSubLabel(mValue.format(mFormatString));
|
||||
}
|
||||
|
||||
//! Update the menu item's sub label to display the template rendered by Home Assistant.
|
||||
//!
|
||||
//! @param data The rendered template (typically a string) to be placed in the sub label. This may
|
||||
//! unusually be a number if the SDK interprets the JSON returned by Home Assistant as such.
|
||||
//
|
||||
function updateState(data as Lang.String or Lang.Dictionary or Lang.Number or Lang.Float or Null) as Void {
|
||||
// If vlue has changed, don't use value from HomeAssitant but display target value
|
||||
if (mValueChanged) {
|
||||
setSubLabel(mValue.format(mFormatString));
|
||||
WatchUi.requestUpdate();
|
||||
return;
|
||||
}
|
||||
if (data == null) {
|
||||
setSubLabel($.Rez.Strings.Empty);
|
||||
} else if(data instanceof Lang.String) {
|
||||
setSubLabel(data);
|
||||
} else if(data instanceof Lang.Number) {
|
||||
var d = data as Lang.Number;
|
||||
setSubLabel(d.format("%d"));
|
||||
} else if(data instanceof Lang.Float) {
|
||||
var f = data as Lang.Float;
|
||||
setSubLabel(f.format(mFormatString));
|
||||
} else if(data instanceof Lang.Dictionary) {
|
||||
// System.println("HomeAssistantMenuItem updateState() data = " + data);
|
||||
if (data.get("error") != null) {
|
||||
setSubLabel($.Rez.Strings.TemplateError);
|
||||
} else {
|
||||
setSubLabel($.Rez.Strings.PotentialError);
|
||||
}
|
||||
} else {
|
||||
// The template must return a Lang.String, Number or Float, or the item cannot be formatted locally without error.
|
||||
setSubLabel(WatchUi.loadResource($.Rez.Strings.TemplateError) as Lang.String);
|
||||
}
|
||||
WatchUi.requestUpdate();
|
||||
}
|
||||
|
||||
//! Set the mValuChanged value.
|
||||
//!
|
||||
//! Can be used to reenable update of subLabel
|
||||
//
|
||||
function setValueChanged(b as Lang.Boolean) as Void {
|
||||
mValueChanged = b;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user