Compare commits

...

8 Commits
v1.5 ... v1.7

Author SHA1 Message Date
8c5aa820ef Update README.md
Added version information for 1.7
2023-12-13 08:53:00 +00:00
a13f04fa6c Merge pull request #28 from j-a-n/confirm_timeout
Auto close confirmation dialog after timeout
2023-12-11 08:22:10 +00:00
143bcf08a7 Add application property "confirm_timeout"
After this time (in seconds), a confirmation dialog for an action is automatically closed and the action is cancelled.
Set to 0 to disable the timeout. The default value is 3 seconds.
2023-12-10 22:52:09 +01:00
ee3b2abed2 Auto close confirmation dialog after timeout 2023-12-10 12:16:01 +01:00
44d5bf8e93 Update README.md 2023-12-06 22:56:59 +00:00
fae2241f01 Merge pull request #24 from house-of-abbey/23-prevent-battery-drain-by-quitting-the-app-after-a-timeout
Initial version with "auto quit"
2023-12-06 22:43:42 +00:00
42e89906f6 Review comments 2023-12-06 22:09:22 +00:00
8c0540ee45 Initial version with "auto quit"
Quit the application after a user settable period of time based on a timeout value from the settings.
2023-12-02 19:04:53 +00:00
9 changed files with 141 additions and 4 deletions

View File

@ -222,3 +222,5 @@ When you change the JSON file defining your dashboard, you must exit the applica
| 1.3 | Tap for scripts was working in emulation but not on some phones. Decision is to make the 'service' field in the JSON compulsory for 'tap' menu items. This is a breaking change, but for many might be a fix for something not working correctly. Improve language support, we can now accept language corrections and prevent the automated translation of strings from clobbering manually refined entries. Thank you to two new contributors. |
| 1.4 | New lean user Interface with thanks to [SomeoneOnEarth](https://github.com/Someone0nEarth) for their contribution which is now the default. If you prefer the old style you can still select it in the settings. The provision of a 'service' tag is now not just heavily suggested by the JSON schema, it is enforced in code. With apologies to anyone suffering a breakage as a result. |
| 1.5 | <img src="images/confirmation_view.jpg" width="200" title="Confirmation View" style="float:right"/> Added an optional confirmation dialogue view to prevent accidental execution of actions on mistaken tap. This also brings a change in the JSON schema to allow an optional field to specify that the confirmation should be used for a menu item. As we are now maturing and adding features we have decided to mitigate breaking changes to the JSON schema by being more careful to adopt the Home Assistant schema (noting there is a 1:1 mapping between YAML and JSON). This change does deprecate the top level `service` tag in favour of `tag_action` containing multiple fields including `service` & `confirm`. Users should migrate to the new format for the new functionality, but the timescale for actual deprecation are long and undecided. |
| 1.6 | Added a user configurable 'timeout' in seconds so that when no action is taken the application automatically closes, stopping the continuous polling for changes of status and hence saving the drain on the battery. This can be disabled with timeout=0. |
| 1.7 | Added timeout to confirmation views so that when used for security devices it does not linger when left unconfirmed. Thanks to [Jan Schneider](https://github.com/j-a-n) for the contribution. Known bug for devices not supporting [`WatchUi.getCurrentView()`](https://developer.garmin.com/connect-iq/api-docs/Toybox/WatchUi.html#getCurrentView-instance_function) API call which is only available on API Level 3.4.0, e.g. Vivoactive 4S. |

View File

@ -24,7 +24,20 @@
<!-- Best be a public URL in order to work away from your home LAN and have a trusted HTTPS certificate -->
<property id="config_url" type="string"></property>
<!--
Application timeout in seconds, except 0 for no timeout (default). After this amount of elapsed time
with no activity, exit the application.
-->
<property id="app_timeout" type="number">0</property>
<!--
After this time (in seconds), a confirmation dialog for an action is automatically closed and the action is cancelled.
Set to 0 to disable the timeout. The default value is 3 seconds.
-->
<property id="confirm_timeout" type="number">3</property>
<property id="types_representation" type="boolean"></property>
<property id="menu_alignment" type="boolean"></property>
</properties>

View File

@ -43,6 +43,26 @@
/>
</setting>
<setting
propertyKey="@Properties.app_timeout"
title="Timeout in seconds. Exit the application after this period of inactivity to save the device battery."
>
<settingConfig
type="numeric"
min="0"
/>
</setting>
<setting
propertyKey="@Properties.confirm_timeout"
title="After this time (in seconds), a confirmation dialog for an action is automatically closed and the action is cancelled. Set to 0 to disable the timeout."
>
<settingConfig
type="numeric"
min="0"
/>
</setting>
<setting
propertyKey="@Properties.types_representation"
title="Representing types with icons (off) or with labels (on)"
@ -60,4 +80,5 @@
type="boolean"
/>
</setting>
</settings>

View File

@ -132,11 +132,13 @@ class AlertDelegate extends WatchUi.InputDelegate {
function onKey(evt) {
mView.dismiss();
getApp().getQuitTimer().reset();
return true;
}
function onTap(evt) {
mView.dismiss();
getApp().getQuitTimer().reset();
return true;
}
}

View File

@ -82,6 +82,7 @@ class ErrorDelegate extends WatchUi.BehaviorDelegate {
WatchUi.BehaviorDelegate.initialize();
}
function onBack() {
getApp().getQuitTimer().reset();
WatchUi.popView(WatchUi.SLIDE_DOWN);
return true;
}

View File

@ -25,6 +25,7 @@ using Toybox.Application.Properties;
class HomeAssistantApp extends Application.AppBase {
private var mHaMenu;
private var quitTimer as QuitTimer;
private var strNoApiKey as Lang.String;
private var strNoApiUrl as Lang.String;
private var strNoConfigUrl as Lang.String;
@ -52,14 +53,18 @@ class HomeAssistantApp extends Application.AppBase {
strConfigUrlNotFound = WatchUi.loadResource($.Rez.Strings.ConfigUrlNotFound);
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr);
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 {}
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>? {
@ -174,6 +179,10 @@ class HomeAssistantApp extends Application.AppBase {
mNextItemToUpdate = (mNextItemToUpdate + 1) % itu.size();
}
function getQuitTimer() as QuitTimer{
return quitTimer;
}
}
function getApp() as HomeAssistantApp {

View File

@ -22,9 +22,10 @@ using Toybox.Lang;
// Required for callback method definition
typedef Method as Toybox.Lang.Method;
using Toybox.WatchUi;
using Toybox.Timer;
using Toybox.Application.Properties;
class HomeAssistantConfirmation extends WatchUi.Confirmation {
function initialize() {
WatchUi.Confirmation.initialize(WatchUi.loadResource($.Rez.Strings.Confirm));
}
@ -33,16 +34,31 @@ class HomeAssistantConfirmation extends WatchUi.Confirmation {
class HomeAssistantConfirmationDelegate extends WatchUi.ConfirmationDelegate {
private var confirmMethod;
private var timeout;
function initialize(callback as Method() as Void) {
WatchUi.ConfirmationDelegate.initialize();
confirmMethod = callback;
var timeoutSeconds = Properties.getValue("confirm_timeout") as Lang.Number;
if (timeoutSeconds > 0) {
timeout = new Timer.Timer();
timeout.start(method(:onTimeout), timeoutSeconds * 1000, true);
}
}
function onResponse(response) as Lang.Boolean {
getApp().getQuitTimer().reset();
if (timeout) {
timeout.stop();
}
if (response == WatchUi.CONFIRM_YES) {
confirmMethod.invoke();
}
return true;
}
function onTimeout() as Void {
timeout.stop();
WatchUi.popView(WatchUi.SLIDE_RIGHT);
}
}

View File

@ -107,7 +107,23 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
Menu2InputDelegate.initialize();
}
function onBack() {
getApp().getQuitTimer().reset();
WatchUi.popView(WatchUi.SLIDE_RIGHT);
}
// Only for CheckboxMenu
function onDone() {
getApp().getQuitTimer().reset();
}
// Only for CustomMenu
function onFooter() {
getApp().getQuitTimer().reset();
}
function onSelect(item as WatchUi.MenuItem) as Void {
getApp().getQuitTimer().reset();
if (item instanceof HomeAssistantToggleMenuItem) {
var haToggleItem = item as HomeAssistantToggleMenuItem;
if (Globals.scDebug) {
@ -147,8 +163,9 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
}
}
function onBack() {
WatchUi.popView(WatchUi.SLIDE_RIGHT);
// Only for CustomMenu
function onTitle() {
getApp().getQuitTimer().reset();
}
}

56
source/QuitTimer.mc Normal file
View File

@ -0,0 +1,56 @@
//-----------------------------------------------------------------------------------
//
// 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.
//
// J D Abbey & P A Abbey, 28 December 2022
//
//
// Description:
//
// Quit the application after a period of inactivity in order to save the battery.
//
//-----------------------------------------------------------------------------------
using Toybox.Lang;
using Toybox.Timer;
using Toybox.Application.Properties;
using Toybox.WatchUi;
class QuitTimer extends Timer.Timer {
private var api_timeout;
function initialize() {
Timer.Timer.initialize();
// Timer needs delay in milliseconds.
api_timeout = (Properties.getValue("app_timeout") as Lang.Number) * 1000;
}
function exitApp() as Void {
if (Globals.scDebug) {
System.println("QuitTimer exitApp(): Exiting");
}
// This will exit the system cleanly from any point within an app.
System.exit();
}
function begin() {
if (api_timeout > 0) {
start(method(:exitApp), api_timeout, false);
}
}
function reset() {
if (Globals.scDebug) {
System.println("QuitTimer reset(): Restarted quit timer");
}
stop();
begin();
}
}