mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-08-03 02:18:34 +00:00
add pin confirmation
This commit is contained in:
@ -85,7 +85,8 @@ class HomeAssistantMenuItemFactory {
|
||||
template as Lang.String or Null,
|
||||
service as Lang.String or Null,
|
||||
confirm as Lang.Boolean,
|
||||
data as Lang.Dictionary or Null
|
||||
data as Lang.Dictionary or Null,
|
||||
pin as Lang.String or Null
|
||||
) as WatchUi.MenuItem {
|
||||
if (entity != null) {
|
||||
if (data == null) {
|
||||
@ -100,6 +101,7 @@ class HomeAssistantMenuItemFactory {
|
||||
template,
|
||||
service,
|
||||
confirm,
|
||||
pin,
|
||||
data,
|
||||
mTapTypeIcon,
|
||||
mMenuItemOptions,
|
||||
@ -111,6 +113,7 @@ class HomeAssistantMenuItemFactory {
|
||||
template,
|
||||
service,
|
||||
confirm,
|
||||
pin,
|
||||
data,
|
||||
mInfoTypeIcon,
|
||||
mMenuItemOptions,
|
||||
|
161
source/HomeAssistantPinConfirmation.mc
Normal file
161
source/HomeAssistantPinConfirmation.mc
Normal file
@ -0,0 +1,161 @@
|
||||
import Toybox.Graphics;
|
||||
import Toybox.Lang;
|
||||
import Toybox.WatchUi;
|
||||
import Toybox.Timer;
|
||||
import Toybox.Attention;
|
||||
|
||||
class PinDigit extends WatchUi.Selectable {
|
||||
|
||||
private var mDigit as Number;
|
||||
|
||||
function initialize(digit as Number, halfX as Number, halfY as Number) {
|
||||
var margin = 40;
|
||||
var x = (digit % 2 == 1) ? 0 + margin : halfX + margin; // place even numbers in right half, odd in left half
|
||||
var y = (digit < 3) ? 0 + margin : halfY + margin; // place 1&2 on top half, 3&4 on bottom half
|
||||
var width = halfX - 2 * margin;
|
||||
var height = halfY - 2 * margin;
|
||||
|
||||
// build text area
|
||||
var textArea = new WatchUi.TextArea({
|
||||
:text=>digit.format("%d"),
|
||||
:color=>Graphics.COLOR_WHITE,
|
||||
:font=>[Graphics.FONT_NUMBER_THAI_HOT, Graphics.FONT_NUMBER_HOT, Graphics.FONT_NUMBER_MEDIUM, Graphics.FONT_NUMBER_MILD],
|
||||
:width=>width,
|
||||
:height=>height,
|
||||
:justification=>Graphics.TEXT_JUSTIFY_CENTER
|
||||
});
|
||||
|
||||
// initialize selectable
|
||||
Selectable.initialize({
|
||||
:stateDefault=>textArea,
|
||||
:locX =>x,
|
||||
:locY=>y,
|
||||
:width=>width,
|
||||
:height=>height
|
||||
});
|
||||
|
||||
mDigit = digit;
|
||||
|
||||
}
|
||||
|
||||
function getDigit() as Number {
|
||||
return mDigit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HomeAssistantPinConfirmationView extends WatchUi.View {
|
||||
|
||||
function initialize() {
|
||||
View.initialize();
|
||||
}
|
||||
|
||||
function onLayout(dc as Dc) as Void {
|
||||
var halfX = dc.getWidth()/2;
|
||||
var halfY = dc.getHeight()/2;
|
||||
// draw digits
|
||||
setLayout([
|
||||
new PinDigit(1, halfX, halfY),
|
||||
new PinDigit(2, halfX, halfY),
|
||||
new PinDigit(3, halfX, halfY),
|
||||
new PinDigit(4, halfX, halfY)
|
||||
]);
|
||||
}
|
||||
|
||||
function onUpdate(dc as Dc) as Void {
|
||||
View.onUpdate(dc);
|
||||
// draw cross
|
||||
var halfX = dc.getWidth()/2;
|
||||
var halfY = dc.getHeight()/2;
|
||||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
|
||||
dc.drawRectangle(halfX, dc.getHeight() * 0.1, 2, dc.getHeight() * 0.8);
|
||||
dc.drawRectangle(dc.getWidth() * 0.1, halfY, dc.getWidth() * 0.8, 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
||||
|
||||
private var mPin as Array<Char>;
|
||||
private var mCurrentIndex as Number;
|
||||
private var mConfirmMethod as Method(state as Lang.Boolean) as Void;
|
||||
private var mTimer as Timer.Timer or Null;
|
||||
private var mState as Lang.Boolean;
|
||||
|
||||
function initialize(callback as Method(state as Lang.Boolean) as Void, state as Lang.Boolean, pin as String) {
|
||||
BehaviorDelegate.initialize();
|
||||
mPin = pin.toCharArray();
|
||||
mCurrentIndex = 0;
|
||||
mConfirmMethod = callback;
|
||||
mState = state;
|
||||
resetTimer();
|
||||
}
|
||||
|
||||
function onSelectable(event as SelectableEvent) as Boolean {
|
||||
var instance = event.getInstance();
|
||||
if (instance instanceof PinDigit && event.getPreviousState() == :stateSelected) {
|
||||
var currentDigit = getTranscodedCurrentDigit();
|
||||
if (currentDigit != null && currentDigit == instance.getDigit()) {
|
||||
// System.println("Pin digit " + (mCurrentIndex+1) + " matches");
|
||||
if (mCurrentIndex == mPin.size()-1) {
|
||||
getApp().getQuitTimer().reset();
|
||||
if (mTimer != null) {
|
||||
mTimer.stop();
|
||||
}
|
||||
mConfirmMethod.invoke(mState);
|
||||
WatchUi.popView(WatchUi.SLIDE_RIGHT);
|
||||
} else {
|
||||
mCurrentIndex++;
|
||||
resetTimer();
|
||||
}
|
||||
} else {
|
||||
// System.println("Pin digit " + (mCurrentIndex+1) + " doesn't match");
|
||||
// TODO: add maxFailures counter & protection
|
||||
error();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTranscodedCurrentDigit() as Number {
|
||||
var currentDigit = mPin[mCurrentIndex].toString().toNumber(); // this is ugly, but apparently the only way for char<->number comparisons
|
||||
// TODO: Transcode digit using a pin mask for additional security
|
||||
return currentDigit;
|
||||
}
|
||||
|
||||
function resetTimer() {
|
||||
var timeout = Settings.getConfirmTimeout(); // ms
|
||||
if (timeout > 0) {
|
||||
if (mTimer != null) {
|
||||
mTimer.stop();
|
||||
} else {
|
||||
mTimer = new Timer.Timer();
|
||||
}
|
||||
mTimer.start(method(:goBack), timeout, true);
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() as Void {
|
||||
if (mTimer != null) {
|
||||
mTimer.stop();
|
||||
}
|
||||
WatchUi.popView(WatchUi.SLIDE_RIGHT);
|
||||
}
|
||||
|
||||
function error() as Void {
|
||||
if (Attention has :vibrate && Settings.getVibrate()) {
|
||||
Attention.vibrate([
|
||||
new Attention.VibeProfile(100, 100),
|
||||
new Attention.VibeProfile(0, 200),
|
||||
new Attention.VibeProfile(75, 100),
|
||||
new Attention.VibeProfile(0, 200),
|
||||
new Attention.VibeProfile(50, 100),
|
||||
new Attention.VibeProfile(0, 200),
|
||||
new Attention.VibeProfile(25, 100)
|
||||
]);
|
||||
}
|
||||
goBack();
|
||||
}
|
||||
|
||||
}
|
@ -28,12 +28,14 @@ class HomeAssistantTapMenuItem extends WatchUi.IconMenuItem {
|
||||
private var mService as Lang.String or Null;
|
||||
private var mConfirm as Lang.Boolean;
|
||||
private var mData as Lang.Dictionary or Null;
|
||||
private var mPin as Lang.String or Null;
|
||||
|
||||
function initialize(
|
||||
label as Lang.String or Lang.Symbol,
|
||||
template as Lang.String,
|
||||
service as Lang.String or Null,
|
||||
confirm as Lang.Boolean,
|
||||
pin as Lang.String or Null,
|
||||
data as Lang.Dictionary or Null,
|
||||
icon as Graphics.BitmapType or WatchUi.Drawable,
|
||||
options as {
|
||||
@ -54,6 +56,7 @@ class HomeAssistantTapMenuItem extends WatchUi.IconMenuItem {
|
||||
mService = service;
|
||||
mConfirm = confirm;
|
||||
mData = data;
|
||||
mPin = pin;
|
||||
}
|
||||
|
||||
function hasTemplate() as Lang.Boolean {
|
||||
@ -84,7 +87,14 @@ class HomeAssistantTapMenuItem extends WatchUi.IconMenuItem {
|
||||
}
|
||||
|
||||
function callService() as Void {
|
||||
if (mConfirm) {
|
||||
var hasTouchScreen = System.getDeviceSettings().isTouchScreen;
|
||||
if (mPin != null && hasTouchScreen) {
|
||||
WatchUi.pushView(
|
||||
new HomeAssistantPinConfirmationView(),
|
||||
new HomeAssistantPinConfirmationDelegate(method(:onConfirm), false, mPin),
|
||||
WatchUi.SLIDE_IMMEDIATE
|
||||
);
|
||||
} else if (mConfirm || (mPin!=null && !hasTouchScreen)) {
|
||||
WatchUi.pushView(
|
||||
new HomeAssistantConfirmation(),
|
||||
new HomeAssistantConfirmationDelegate(method(:onConfirm), false),
|
||||
|
@ -52,10 +52,12 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
var service = items[i].get("service") as Lang.String or Null; // Deprecated schema
|
||||
var confirm = false as Lang.Boolean or Null;
|
||||
var data = null as Lang.Dictionary or Null;
|
||||
var pin = null as Lang.String or Null;
|
||||
if (tap_action != null) {
|
||||
service = tap_action.get("service");
|
||||
confirm = tap_action.get("confirm"); // Optional
|
||||
data = tap_action.get("data"); // Optional
|
||||
pin = tap_action.get("pin"); // Optional
|
||||
if (confirm == null) {
|
||||
confirm = false;
|
||||
}
|
||||
@ -64,7 +66,7 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
if (type.equals("toggle") && entity != null) {
|
||||
addItem(HomeAssistantMenuItemFactory.create().toggle(name, entity, content, confirm));
|
||||
} else if ((type.equals("tap") && service != null) || (type.equals("template") && content != null)) {
|
||||
addItem(HomeAssistantMenuItemFactory.create().tap(name, entity, content, service, confirm, data));
|
||||
addItem(HomeAssistantMenuItemFactory.create().tap(name, entity, content, service, confirm, data, pin));
|
||||
} else if (type.equals("group")) {
|
||||
addItem(HomeAssistantMenuItemFactory.create().group(items[i], content));
|
||||
}
|
||||
|
Reference in New Issue
Block a user