We have three physical buttons, and some "control" on the right hand two buttons.
Is it possible to place an onclick/onactivate event hook onto the left hand button?
For example, we want confirmation from the user that they actually do want to exit the application, rather than lose all their collected activity data.
Thanks
Answered! Go to the Best Answer.
Best Answer
Just put together a little test to remap the "back" button to the "top" button.
So it is entirely possible to prevent accidental exit from the application.
Thanks to those who helped out on this ![]()
import document from "document";
import { me } from "appbit";
document.onkeypress = function(e) {
console.log("Key pressed: " + e.key);
e.preventDefault();
if (e.key==="up") {
console.log("trapped");
me.exit();
}Have updated this post to show a full solution in the hope it helps someone out in the community:
app/index.js
import document from "document";
import { me } from "appbit";
import clock from "clock";
let runningPage = document.getElementById("runningPage");
let exitPage = document.getElementById("exitPage");
let timeDisplay = document.getElementById("time");
let dateDisplay = document.getElementById("date");
let btnyes = document.getElementById("btn-yes");
btnyes.onclick = function(evt) {
me.exit();
}
let btnno = document.getElementById("btn-no");
btnno.onclick = function(evt) {
runningPage.style.display="inline";
exitPage.style.display="none";
}
runningPage.style.display="inline";
exitPage.style.display="none";
document.onkeypress = function(e) {
e.preventDefault();
if (e.key=="up" && exitPage.style.display=="inline") {
me.exit();
}
if (e.key==="back" || e.key==="down") {
if (exitPage.style.display==="inline") {
runningPage.style.display="inline";
exitPage.style.display="none";
} else {
runningPage.style.display="none";
exitPage.style.display="inline";
}
}
}
clock.granularity = "seconds";
clock.ontick = () => showData();
function showData() {
let myDate=new Date();
let secs=zeroPad(myDate.getSeconds());
let mins=zeroPad(myDate.getMinutes());
let hrs=myDate.getHours();
let day=zeroPad(myDate.getDate());
let month=zeroPad(myDate.getMonth()+1);
let year=zeroPad(myDate.getFullYear());
timeDisplay.text=`${hrs}:${mins}:${secs}`;
dateDisplay.text=`${day}/${month}/${year}`;
}
function zeroPad(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
resources/index.gui
<svg>
<svg id="runningPage">
<rect id="background2" pointer-events="none" />
<text y="110" x="50%" id="Title" font-family="System-Regular" fill="yellow" font-size="45" font-weight="bold" text-anchor="middle">Clock</text>
<text y="160" x="50%" id="time" font-family="System-Regular" fill="white" font-size="40" font-weight="bold" text-length="20" text-anchor="middle">Time: </text>
<text y="195" x="50%" id="date" font-family="System-Regular" fill="white" font-size="40" font-weight="bold" text-length="20" text-anchor="middle">Date: </text>
</svg>
<svg id="exitPage">
<text y="110" x="50%" id="Title" font-family="System-Regular" fill="yellow" font-size="45" font-weight="bold" text-anchor="middle">Exit: Are you sure?</text>
<svg y="$">
<use id="btn-yes" href="#square-button-toggle" x="50%" fill="fb-green">
<set href="#text" attributeName="text-buffer" to="Yes" />
</use>
<use id="btn-no" href="#square-button-toggle" value="1" fill="fb-red">
<set href="#text" attributeName="text-buffer" to="No" />
</use>
</svg>
</svg>
</svg>
resource/widgets.gui
<svg>
<defs>
<link rel="import" href="/mnt/sysassets/widgets_common.gui" />
<link rel="import" href="/mnt/sysassets/widgets/square_button_widget.gui" />
<link rel="import" href="/mnt/sysassets/widgets/baseview_widget.gui" />
</defs>
</svg>
That should be pretty much all you need. Press the back button to display the exit confirmation screen and then tap either of the two displayed buttons, or click back / down physical buttons to cancel exiting or the top button to confirm exit.
Running Page
Exit Confirmation Page
You add events to physical buttons. You can add an onunload event with the AppBit API and save data there.
Best AnswerThank you FredFitbit.
Is mapping the left button in the development plan? The right hand two are effectively mapped against the right hand combo buttons.
At the moment it is too easy to accidentally exit the application when you didn't actually mean to (mid run when you tap the button to wake up but accidentally hit it twice --- frustrating.
Some thought would need to be given to prevent malicious code from stopping a user exiting an application. A double tap on the left button for example ....
Best AnswerI think the answer for an app is described here:
https://dev.fitbit.com/guides/user-interface/javascript/#using-the-physical-buttons
The document object emits keypress events when the user presses one of the physical buttons. Long press button events are reserved for system use only.
import document from "document"; document.onkeypress = function(e) { console.log("Key pressed: " + e.key); }
The possible values for e.key are down, up, and back.
My bad, it's only long press that are reserved for the system, I updated my answer, thaks @qooApps .
Best AnswerThank you qooApps for your reply and useful information - help like this from the community is genuinely appreciated.
This however doesn't solve the issue with accidentally closing the application.
Yes indeed you do get a 'back' event firing - which you can save data automatically.- but how can you then present a "Are You Sure?" with a Yes / No selection.
Is this something that FitBit has in their development pathway?
Best AnswerYou can prevent the default action of the back button (“exiting the app”) by using event.preventDefault() inside the onkeypressfunction but I’m not sure how to close the app programatically
document.onkeypress = function(evt) {
if (evt.key === "back") {
evt.preventDefault();
// display confirmation message
}
}
Thank you pautomas.
It would be good to know if there is a way to close the app programatically.
In the meantime it would be possible, when clicking the back button, to check whether the user has previously clicked and positively responded to a "are you sure message?" If they have then allow exit, otherwise evt.preventDefault() would be executed.
Clunky - but workable.
Best Answer
Just put together a little test to remap the "back" button to the "top" button.
So it is entirely possible to prevent accidental exit from the application.
Thanks to those who helped out on this ![]()
import document from "document";
import { me } from "appbit";
document.onkeypress = function(e) {
console.log("Key pressed: " + e.key);
e.preventDefault();
if (e.key==="up") {
console.log("trapped");
me.exit();
}Have updated this post to show a full solution in the hope it helps someone out in the community:
app/index.js
import document from "document";
import { me } from "appbit";
import clock from "clock";
let runningPage = document.getElementById("runningPage");
let exitPage = document.getElementById("exitPage");
let timeDisplay = document.getElementById("time");
let dateDisplay = document.getElementById("date");
let btnyes = document.getElementById("btn-yes");
btnyes.onclick = function(evt) {
me.exit();
}
let btnno = document.getElementById("btn-no");
btnno.onclick = function(evt) {
runningPage.style.display="inline";
exitPage.style.display="none";
}
runningPage.style.display="inline";
exitPage.style.display="none";
document.onkeypress = function(e) {
e.preventDefault();
if (e.key=="up" && exitPage.style.display=="inline") {
me.exit();
}
if (e.key==="back" || e.key==="down") {
if (exitPage.style.display==="inline") {
runningPage.style.display="inline";
exitPage.style.display="none";
} else {
runningPage.style.display="none";
exitPage.style.display="inline";
}
}
}
clock.granularity = "seconds";
clock.ontick = () => showData();
function showData() {
let myDate=new Date();
let secs=zeroPad(myDate.getSeconds());
let mins=zeroPad(myDate.getMinutes());
let hrs=myDate.getHours();
let day=zeroPad(myDate.getDate());
let month=zeroPad(myDate.getMonth()+1);
let year=zeroPad(myDate.getFullYear());
timeDisplay.text=`${hrs}:${mins}:${secs}`;
dateDisplay.text=`${day}/${month}/${year}`;
}
function zeroPad(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
resources/index.gui
<svg>
<svg id="runningPage">
<rect id="background2" pointer-events="none" />
<text y="110" x="50%" id="Title" font-family="System-Regular" fill="yellow" font-size="45" font-weight="bold" text-anchor="middle">Clock</text>
<text y="160" x="50%" id="time" font-family="System-Regular" fill="white" font-size="40" font-weight="bold" text-length="20" text-anchor="middle">Time: </text>
<text y="195" x="50%" id="date" font-family="System-Regular" fill="white" font-size="40" font-weight="bold" text-length="20" text-anchor="middle">Date: </text>
</svg>
<svg id="exitPage">
<text y="110" x="50%" id="Title" font-family="System-Regular" fill="yellow" font-size="45" font-weight="bold" text-anchor="middle">Exit: Are you sure?</text>
<svg y="$">
<use id="btn-yes" href="#square-button-toggle" x="50%" fill="fb-green">
<set href="#text" attributeName="text-buffer" to="Yes" />
</use>
<use id="btn-no" href="#square-button-toggle" value="1" fill="fb-red">
<set href="#text" attributeName="text-buffer" to="No" />
</use>
</svg>
</svg>
</svg>
resource/widgets.gui
<svg>
<defs>
<link rel="import" href="/mnt/sysassets/widgets_common.gui" />
<link rel="import" href="/mnt/sysassets/widgets/square_button_widget.gui" />
<link rel="import" href="/mnt/sysassets/widgets/baseview_widget.gui" />
</defs>
</svg>
That should be pretty much all you need. Press the back button to display the exit confirmation screen and then tap either of the two displayed buttons, or click back / down physical buttons to cancel exiting or the top button to confirm exit.
Running Page
Exit Confirmation Page
Moved content into the post above. Apologies for duplicating.
Best Answer