mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-08-04 02:48:41 +00:00
Internationalisation & Multi-watch support
Copied two methods from GarminThermoNest to translate languages and manage different sized icons for the various sizes of watch. Also copied ErrorView for smaller wrapped text for error messages.
This commit is contained in:
88
source/ErrorView.mc
Normal file
88
source/ErrorView.mc
Normal file
@ -0,0 +1,88 @@
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// ErrorView provides a means to present application errors to the user. These
|
||||
// should not happen of course... but they do, so best make sure errors can be
|
||||
// reported.
|
||||
//
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
using Toybox.Graphics;
|
||||
using Toybox.Lang;
|
||||
using Toybox.WatchUi;
|
||||
using Toybox.Communications;
|
||||
|
||||
class ErrorView extends ScalableView {
|
||||
hidden const settings as Lang.Dictionary = {
|
||||
:errorIconMargin => 7f
|
||||
};
|
||||
// Vertical spacing between the top of the face and the error icon
|
||||
hidden var errorIconMargin;
|
||||
hidden var text as Lang.String;
|
||||
hidden var errorIcon;
|
||||
hidden var textArea;
|
||||
|
||||
function initialize(text as Lang.String) {
|
||||
ScalableView.initialize();
|
||||
self.text = text;
|
||||
// Convert the settings from % of screen size to pixels
|
||||
errorIconMargin = pixelsForScreen(settings.get(:errorIconMargin) as Lang.Float);
|
||||
}
|
||||
|
||||
// Load your resources here
|
||||
function onLayout(dc as Graphics.Dc) as Void {
|
||||
errorIcon = Application.loadResource(Rez.Drawables.ErrorIcon) as Graphics.BitmapResource;
|
||||
|
||||
var w = dc.getWidth();
|
||||
var h = dc.getHeight();
|
||||
|
||||
textArea = new WatchUi.TextArea({
|
||||
:text => text,
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => 0,
|
||||
:locY => 83,
|
||||
:width => w,
|
||||
:height => h - 166
|
||||
});
|
||||
}
|
||||
|
||||
// Update the view
|
||||
function onUpdate(dc as Graphics.Dc) as Void {
|
||||
var w = dc.getWidth();
|
||||
var hw = w/2;
|
||||
var bg = 0x3B444C;
|
||||
if(dc has :setAntiAlias) {
|
||||
dc.setAntiAlias(true);
|
||||
}
|
||||
dc.setColor(Graphics.COLOR_WHITE, bg);
|
||||
dc.clear();
|
||||
dc.drawBitmap(hw - errorIcon.getWidth()/2, errorIconMargin, errorIcon);
|
||||
textArea.draw(dc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ErrorDelegate extends WatchUi.BehaviorDelegate {
|
||||
function initialize() {
|
||||
WatchUi.BehaviorDelegate.initialize();
|
||||
}
|
||||
function onBack() {
|
||||
WatchUi.popView(WatchUi.SLIDE_DOWN);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -25,5 +25,6 @@ class Globals {
|
||||
// as the messages can't be read from a watch!)
|
||||
static const debug = false;
|
||||
static const updateInterval = 5; // seconds
|
||||
static const alertTimeout = 1000; // ms
|
||||
static const alertTimeout = 2000; // ms
|
||||
static const tapTimeout = 1000; // ms
|
||||
}
|
||||
|
@ -26,11 +26,15 @@ using Toybox.Timer;
|
||||
|
||||
class HomeAssistantApp extends Application.AppBase {
|
||||
hidden var haMenu;
|
||||
hidden var strNoInternet as Lang.String;
|
||||
hidden var strNoMenu as Lang.String;
|
||||
hidden var timer as Timer.Timer;
|
||||
|
||||
function initialize() {
|
||||
AppBase.initialize();
|
||||
timer = new Timer.Timer();
|
||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu);
|
||||
timer = new Timer.Timer();
|
||||
}
|
||||
|
||||
// onStart() is called on application start up
|
||||
@ -69,13 +73,7 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
if (Globals.debug) {
|
||||
System.println("HomeAssistantApp Note - onReturnFetchMenuConfig(): Configuration not found or potential validation issue.");
|
||||
}
|
||||
new Alert({
|
||||
:timeout => Globals.alertTimeout,
|
||||
:font => Graphics.FONT_SYSTEM_MEDIUM,
|
||||
:text => "onReturnFetchMenuConfig Error " + responseCode,
|
||||
:fgcolor => Graphics.COLOR_RED,
|
||||
:bgcolor => Graphics.COLOR_BLACK
|
||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||
WatchUi.pushView(new ErrorView(strNoMenu + " code=" + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +96,7 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
new Alert({
|
||||
:timeout => Globals.alertTimeout,
|
||||
:font => Graphics.FONT_SYSTEM_MEDIUM,
|
||||
:text => "No Internet connection",
|
||||
:text => strNoInternet,
|
||||
:fgcolor => Graphics.COLOR_RED,
|
||||
:bgcolor => Graphics.COLOR_BLACK
|
||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||
|
@ -25,6 +25,7 @@ using Toybox.Application.Properties;
|
||||
|
||||
class HomeAssistantMenuItem extends WatchUi.MenuItem {
|
||||
hidden var api_key = Properties.getValue("api_key");
|
||||
hidden var strNoInternet as Lang.String;
|
||||
|
||||
function initialize(
|
||||
label as Lang.String or Lang.Symbol,
|
||||
@ -35,6 +36,7 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
|
||||
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
|
||||
} or Null
|
||||
) {
|
||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
WatchUi.MenuItem.initialize(
|
||||
label,
|
||||
subLabel,
|
||||
@ -58,7 +60,7 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
|
||||
System.println("HomeAssistantMenuItem Note - onReturnExecScript(): Correct script executed.");
|
||||
}
|
||||
new Alert({
|
||||
:timeout => Globals.alertTimeout,
|
||||
:timeout => Globals.tapTimeout,
|
||||
:font => Graphics.FONT_SYSTEM_MEDIUM,
|
||||
:text => (d[i].get("attributes") as Lang.Dictionary).get("friendly_name"),
|
||||
:fgcolor => Graphics.COLOR_WHITE,
|
||||
@ -96,7 +98,7 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
|
||||
new Alert({
|
||||
:timeout => Globals.alertTimeout,
|
||||
:font => Graphics.FONT_SYSTEM_MEDIUM,
|
||||
:text => "No Internet connection",
|
||||
:text => strNoInternet,
|
||||
:fgcolor => Graphics.COLOR_RED,
|
||||
:bgcolor => Graphics.COLOR_BLACK
|
||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||
|
@ -25,6 +25,7 @@ using Toybox.Application.Properties;
|
||||
|
||||
class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
hidden var api_key = Properties.getValue("api_key");
|
||||
hidden var strNoInternet as Lang.String;
|
||||
|
||||
function initialize(
|
||||
label as Lang.String or Lang.Symbol,
|
||||
@ -39,6 +40,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
|
||||
} or Null
|
||||
) {
|
||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
WatchUi.ToggleMenuItem.initialize(label, subLabel, identifier, enabled, options);
|
||||
api_key = Properties.getValue("api_key");
|
||||
}
|
||||
@ -100,7 +102,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
new Alert({
|
||||
:timeout => Globals.alertTimeout,
|
||||
:font => Graphics.FONT_SYSTEM_MEDIUM,
|
||||
:text => "No Internet connection",
|
||||
:text => strNoInternet,
|
||||
:fgcolor => Graphics.COLOR_RED,
|
||||
:bgcolor => Graphics.COLOR_BLACK
|
||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||
@ -164,7 +166,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
new Alert({
|
||||
:timeout => Globals.alertTimeout,
|
||||
:font => Graphics.FONT_SYSTEM_MEDIUM,
|
||||
:text => "No Internet connection",
|
||||
:text => strNoInternet,
|
||||
:fgcolor => Graphics.COLOR_RED,
|
||||
:bgcolor => Graphics.COLOR_BLACK
|
||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||
|
@ -23,6 +23,7 @@ using Toybox.Graphics;
|
||||
using Toybox.WatchUi;
|
||||
|
||||
class HomeAssistantView extends WatchUi.Menu2 {
|
||||
hidden var strMenuItemTap as Lang.String;
|
||||
|
||||
function initialize(
|
||||
definition as Lang.Dictionary,
|
||||
@ -32,9 +33,10 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
:theme as WatchUi.MenuTheme or Null
|
||||
} or Null
|
||||
) {
|
||||
strMenuItemTap = WatchUi.loadResource($.Rez.Strings.MenuItemTap);
|
||||
var toggle_obj = {
|
||||
:enabled => "On",
|
||||
:disabled => "Off"
|
||||
:enabled => WatchUi.loadResource($.Rez.Strings.MenuItemOn) as Lang.String,
|
||||
:disabled => WatchUi.loadResource($.Rez.Strings.MenuItemOff) as Lang.String
|
||||
};
|
||||
|
||||
if (options == null) {
|
||||
@ -66,7 +68,7 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
addItem(
|
||||
new HomeAssistantMenuItem(
|
||||
name,
|
||||
"Tap",
|
||||
strMenuItemTap,
|
||||
entity,
|
||||
null
|
||||
)
|
||||
@ -115,6 +117,9 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Reference: https://developer.garmin.com/connect-iq/core-topics/input-handling/
|
||||
//
|
||||
class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
|
||||
|
||||
function initialize() {
|
||||
|
@ -28,7 +28,7 @@ class HomeAssistantViewMenuItem extends WatchUi.MenuItem {
|
||||
// definitions.get(...) are Strings here as they have been checked by HomeAssistantView first
|
||||
WatchUi.MenuItem.initialize(
|
||||
definition.get("name") as Lang.String,
|
||||
"Menu",
|
||||
WatchUi.loadResource($.Rez.Strings.MenuItemMenu) as Lang.String,
|
||||
definition.get("entity") as Lang.String,
|
||||
null
|
||||
);
|
||||
|
48
source/ScalableView.mc
Normal file
48
source/ScalableView.mc
Normal file
@ -0,0 +1,48 @@
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// A view with added methods to scale from percentages of scrren size to pixels.
|
||||
//
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
using Toybox.Lang;
|
||||
using Toybox.WatchUi;
|
||||
using Toybox.Math;
|
||||
|
||||
class ScalableView extends WatchUi.View {
|
||||
hidden var screenWidth;
|
||||
|
||||
function initialize() {
|
||||
View.initialize();
|
||||
}
|
||||
|
||||
// Convert a fraction expressed as a percentage (%) to a number of pixels for the
|
||||
// screen's dimensions.
|
||||
//
|
||||
// Parameters:
|
||||
// * dc - Device context
|
||||
// * pc - Percentage (%) expressed as a number in the range 0.0..100.0
|
||||
//
|
||||
// Uses screen width rather than screen height as rectangular screens tend to have
|
||||
// height > width.
|
||||
//
|
||||
function pixelsForScreen(pc as Lang.Float) as Lang.Number {
|
||||
if (screenWidth == null) {
|
||||
screenWidth = System.getDeviceSettings().screenWidth;
|
||||
}
|
||||
return Math.round(pc * screenWidth) / 100;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user