mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-04-30 12:42:27 +00:00
use full numpad, validate 4-digit pin, add visual feedback on click, show toast on error
This commit is contained in:
@ -39,7 +39,8 @@
|
||||
des Geräts zu schonen.</string>
|
||||
<string id="SettingsConfirmTimeout">Nach dieser Zeit (in Sekunden) wird der Bestätigungsdialog einer Aktion geschlossen und die
|
||||
Aktion abgebrochen. Auf 0 setzen, um den Timeout zu deaktivieren.</string>
|
||||
<string id="SettingsPin">PIN für alle Actions mit 'confirm': true.</string>
|
||||
<string id="SettingsPin">4-stellige PIN für alle Actions mit 'confirm': true (0000-9999).</string>
|
||||
<string id="SettingsPinError">Bitte eine gültige 4-stellige numerische PIN in den App Einstellungen eingeben (0000-4444).</string>
|
||||
<string id="SettingsWidgetStart">(Nur Widget) Anwendung automatisch über das Widget starten ohne drauftippen zu müssen.</string>
|
||||
<string id="SettingsEnableBatteryLevel">Hintergrunddienst aktivieren, um den Ladezustand der Batterie an HomeAssistant zu senden.</string>
|
||||
<string id="SettingsBatteryLevelRefreshRate">Die Aktualisierungsrate (in Minuten) mit der der Ladezustand der Batterie
|
||||
|
@ -42,6 +42,7 @@
|
||||
<string id="PotentialError">Potential Error</string>
|
||||
<string id="PinInputLocked">PIN input locked for</string>
|
||||
<string id="Seconds">seconds</string>
|
||||
<string id="WrongPin">Wrong PIN</string>
|
||||
|
||||
<!-- For the settings GUI -->
|
||||
<string id="SettingsSelect">Select...</string>
|
||||
@ -55,7 +56,8 @@
|
||||
<string id="SettingsAppTimeout">Timeout in seconds. Exit the application after this period of inactivity to save the device battery.</string>
|
||||
<string id="SettingsPollDelay">Additional poll delay (in seconds). Adds a delay between the status update of all menu items.</string>
|
||||
<string id="SettingsConfirmTimeout">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.</string>
|
||||
<string id="SettingsPin">PIN to be used for all actions that require confirmation.</string>
|
||||
<string id="SettingsPin">4-digit PIN to be used for all actions that require confirmation (0000-9999).</string>
|
||||
<string id="SettingsPinError">Please configure a valid 4-digit numeric PIN between 0000 and 9999 in the application settings.</string>
|
||||
<string id="SettingsTextAlign">Left (off) or Right (on) Menu Alignment.</string>
|
||||
<string id="LeftToRight">Left to right</string>
|
||||
<string id="RightToLeft">Right to Left</string>
|
||||
|
@ -29,26 +29,33 @@ 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;
|
||||
function initialize(digit as Number, stepX as Number, stepY as Number) {
|
||||
var marginX = stepX * 0.05; // 5% margin on all sides
|
||||
var marginY = stepY * 0.05;
|
||||
var x = (digit == 0) ? stepX : stepX * ((digit+2) % 3); // layout '0' in 2nd col, others ltr in 3 columns
|
||||
x += marginX + HomeAssistantPinConfirmationView.MARGIN_X;
|
||||
var y = (digit == 0) ? stepY * 4 : (digit <= 3) ? stepY : (digit <=6) ? stepY * 2 : stepY * 3; // layout '0' in bottom row (5), others top to bottom in 3 rows (2-4) (row 1 is reserved for masked pin)
|
||||
y += marginY;
|
||||
var width = stepX - (marginX * 2);
|
||||
var height = stepY - (marginY * 2);
|
||||
|
||||
// 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],
|
||||
var button = new PinDigitButton({
|
||||
:width=>width,
|
||||
:height=>height,
|
||||
:justification=>Graphics.TEXT_JUSTIFY_CENTER
|
||||
:label=>digit
|
||||
});
|
||||
|
||||
var buttonTouched = new PinDigitButton({
|
||||
:width=>width,
|
||||
:height=>height,
|
||||
:label=>digit,
|
||||
:touched=>true
|
||||
});
|
||||
|
||||
// initialize selectable
|
||||
Selectable.initialize({
|
||||
:stateDefault=>textArea,
|
||||
:stateDefault=>button,
|
||||
:stateHighlighted=>buttonTouched,
|
||||
:locX =>x,
|
||||
:locY=>y,
|
||||
:width=>width,
|
||||
@ -63,34 +70,69 @@ class PinDigit extends WatchUi.Selectable {
|
||||
return mDigit;
|
||||
}
|
||||
|
||||
class PinDigitButton extends WatchUi.Drawable {
|
||||
private var mText as Number;
|
||||
private var mTouched as Boolean = false;
|
||||
|
||||
function initialize(options) {
|
||||
Drawable.initialize(options);
|
||||
mText = options.get(:label);
|
||||
mTouched = options.get(:touched);
|
||||
}
|
||||
|
||||
function draw(dc) {
|
||||
if (mTouched) {
|
||||
dc.setColor(Graphics.COLOR_ORANGE, Graphics.COLOR_ORANGE);
|
||||
} else {
|
||||
dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_DK_GRAY);
|
||||
}
|
||||
dc.fillCircle(locX + width / 2, locY + height / 2, height / 2); // circle fill
|
||||
dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_LT_GRAY);
|
||||
dc.setPenWidth(3);
|
||||
dc.drawCircle(locX + width / 2, locY + height / 2, height / 2); // circle outline
|
||||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(locX+width / 2, locY+height / 2, Graphics.FONT_TINY, mText, Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER); // center text in circle
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HomeAssistantPinConfirmationView extends WatchUi.View {
|
||||
|
||||
static const MARGIN_X = 20; // margin on left & right side of screen (overall prettier and works better on round displays)
|
||||
|
||||
var mPinMask as String = "";
|
||||
|
||||
function initialize() {
|
||||
View.initialize();
|
||||
}
|
||||
|
||||
function onLayout(dc as Dc) as Void {
|
||||
var halfX = dc.getWidth()/2;
|
||||
var halfY = dc.getHeight()/2;
|
||||
var stepX = (dc.getWidth() - MARGIN_X * 2) / 3; // three columns
|
||||
var stepY = dc.getHeight() / 5; // five rows (first row for masked pin entry)
|
||||
var digits = [];
|
||||
for (var i=0; i<=9; i++) {
|
||||
digits.add(new PinDigit(i, stepX, stepY));
|
||||
}
|
||||
// draw digits
|
||||
setLayout([
|
||||
new PinDigit(1, halfX, halfY),
|
||||
new PinDigit(2, halfX, halfY),
|
||||
new PinDigit(3, halfX, halfY),
|
||||
new PinDigit(4, halfX, halfY)
|
||||
]);
|
||||
setLayout(digits);
|
||||
}
|
||||
|
||||
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);
|
||||
if (mPinMask.length() != 0) {
|
||||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
|
||||
dc.drawText(dc.getWidth()/2, dc.getHeight()/10, Graphics.FONT_SYSTEM_SMALL, mPinMask, Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePinMask(length as Number) {
|
||||
mPinMask = "";
|
||||
for (var i=0; i<length; i++) {
|
||||
mPinMask += "*";
|
||||
}
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
@ -104,8 +146,9 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
||||
private var mTimer as Timer.Timer or Null;
|
||||
private var mState as Lang.Boolean;
|
||||
private var mFailures as PinFailures;
|
||||
private var mView as HomeAssistantPinConfirmationView;
|
||||
|
||||
function initialize(callback as Method(state as Lang.Boolean) as Void, state as Lang.Boolean, pin as String) {
|
||||
function initialize(callback as Method(state as Lang.Boolean) as Void, state as Lang.Boolean, pin as String, view as HomeAssistantPinConfirmationView) {
|
||||
BehaviorDelegate.initialize();
|
||||
mFailures = new PinFailures();
|
||||
if (mFailures.isLocked()) {
|
||||
@ -118,6 +161,7 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
||||
mEnteredPin = "";
|
||||
mConfirmMethod = callback;
|
||||
mState = state;
|
||||
mView = view;
|
||||
resetTimer();
|
||||
}
|
||||
|
||||
@ -127,10 +171,8 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
||||
}
|
||||
var instance = event.getInstance();
|
||||
if (instance instanceof PinDigit && event.getPreviousState() == :stateSelected) {
|
||||
if (Attention has :vibrate && Settings.getVibrate()) {
|
||||
Attention.vibrate([new Attention.VibeProfile(25, 25)]);
|
||||
}
|
||||
mEnteredPin += instance.getDigit();
|
||||
createUserFeedback();
|
||||
// System.println("HomeAssitantPinConfirmationDelegate onSelectable() mEnteredPin = " + mEnteredPin);
|
||||
if (mEnteredPin.length() == mPin.length()) {
|
||||
if (mEnteredPin.equals(mPin)) {
|
||||
@ -151,6 +193,13 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
||||
return true;
|
||||
}
|
||||
|
||||
function createUserFeedback() {
|
||||
if (Attention has :vibrate && Settings.getVibrate()) {
|
||||
Attention.vibrate([new Attention.VibeProfile(25, 25)]);
|
||||
}
|
||||
mView.updatePinMask(mEnteredPin.length());
|
||||
}
|
||||
|
||||
function resetTimer() {
|
||||
var timeout = Settings.getConfirmTimeout(); // ms
|
||||
if (timeout > 0) {
|
||||
@ -159,7 +208,7 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
||||
} else {
|
||||
mTimer = new Timer.Timer();
|
||||
}
|
||||
mTimer.start(method(:goBack), timeout, true);
|
||||
mTimer.start(method(:goBack), timeout, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,6 +233,9 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
||||
new Attention.VibeProfile(25, 100)
|
||||
]);
|
||||
}
|
||||
if (WatchUi has :showToast) {
|
||||
showToast($.Rez.Strings.WrongPin, null);
|
||||
}
|
||||
goBack();
|
||||
}
|
||||
|
||||
|
@ -94,9 +94,14 @@ class HomeAssistantTapMenuItem extends WatchUi.IconMenuItem {
|
||||
WatchUi.SLIDE_IMMEDIATE
|
||||
);
|
||||
} else {
|
||||
if (pin.toNumber() == null || pin.length() != 4) {
|
||||
ErrorView.show(WatchUi.loadResource($.Rez.Strings.SettingsPinError) as Lang.String);
|
||||
return;
|
||||
}
|
||||
var pinConfirmationView = new HomeAssistantPinConfirmationView();
|
||||
WatchUi.pushView(
|
||||
new HomeAssistantPinConfirmationView(),
|
||||
new HomeAssistantPinConfirmationDelegate(method(:onConfirm), false, pin),
|
||||
pinConfirmationView,
|
||||
new HomeAssistantPinConfirmationDelegate(method(:onConfirm), false, pin, pinConfirmationView),
|
||||
WatchUi.SLIDE_IMMEDIATE
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user