Merge pull request #15 from Someone0nEarth/lean_ui
Icons for Menu Types
@ -21,7 +21,7 @@
|
|||||||
Use "Monkey C: Edit Application" from the Visual Studio Code command palette
|
Use "Monkey C: Edit Application" from the Visual Studio Code command palette
|
||||||
to update the application attributes.
|
to update the application attributes.
|
||||||
-->
|
-->
|
||||||
<iq:application id="98c36259-498a-4458-9cef-74a273ad2bc3" type="watch-app" name="@Strings.AppName" entry="HomeAssistantApp" launcherIcon="@Drawables.LauncherIcon" minApiLevel="3.1.0">
|
<iq:application id="40131e87-31ff-454b-a8e2-92276ee399d6" type="watch-app" name="@Strings.AppName" entry="HomeAssistantApp" launcherIcon="@Drawables.LauncherIcon" minApiLevel="3.1.0">
|
||||||
<!--
|
<!--
|
||||||
Use the following from the Visual Studio Code comand palette to edit
|
Use the following from the Visual Studio Code comand palette to edit
|
||||||
the build targets:
|
the build targets:
|
||||||
|
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-18/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="18" viewBox="0 -960 960 960" width="18" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-18/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="18" viewBox="0 -960 960 960" width="18" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-21/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="21" viewBox="0 -960 960 960" width="21" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-21/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="21" viewBox="0 -960 960 960" width="21" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-24/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="24" viewBox="0 -960 960 960" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-24/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="24" viewBox="0 -960 960 960" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-26/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="26" viewBox="0 -960 960 960" width="26" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-26/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="26" viewBox="0 -960 960 960" width="26" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-28/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="28" viewBox="0 -960 960 960" width="28" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-28/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="28" viewBox="0 -960 960 960" width="28" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-30/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="30" viewBox="0 -960 960 960" width="30" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-30/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="30" viewBox="0 -960 960 960" width="30" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-32/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="32" viewBox="0 -960 960 960" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-32/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="32" viewBox="0 -960 960 960" width="32" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-38/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="38" viewBox="0 -960 960 960" width="38" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-38/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="38" viewBox="0 -960 960 960" width="38" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-42/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="42" viewBox="0 -960 960 960" width="42" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-42/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="42" viewBox="0 -960 960 960" width="42" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-46/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="46" viewBox="0 -960 960 960" width="46" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-46/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="46" viewBox="0 -960 960 960" width="46" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-48/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 606 B |
1
resources-icons-48/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 782 B |
@ -17,4 +17,6 @@
|
|||||||
|
|
||||||
<drawables>
|
<drawables>
|
||||||
<bitmap id="ErrorIcon" filename="error.svg"/>
|
<bitmap id="ErrorIcon" filename="error.svg"/>
|
||||||
|
<bitmap id="GroupTypeIcon" filename="group_type.svg"/>
|
||||||
|
<bitmap id="TapTypeIcon" filename="tap_type.svg"/>
|
||||||
</drawables>
|
</drawables>
|
1
resources-icons-53/group_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="53" viewBox="0 -960 960 960" width="53" xmlns="http://www.w3.org/2000/svg"><path d="M479.858-160Q460-160 446-174.142q-14-14.141-14-34Q432-228 446.142-242q14.141-14 34-14Q500-256 514-241.858q14 14.141 14 34Q528-188 513.858-174q-14.141 14-34 14Zm0-272Q460-432 446-446.142q-14-14.141-14-34Q432-500 446.142-514q14.141-14 34-14Q500-528 514-513.858q14 14.141 14 34Q528-460 513.858-446q-14.141 14-34 14Zm0-272Q460-704 446-718.142q-14-14.141-14-34Q432-772 446.142-786q14.141-14 34-14Q500-800 514-785.858q14 14.141 14 34Q528-732 513.858-718q-14.141 14-34 14Z" fill="darkgrey" stroke="darkgrey"/></svg>
|
After Width: | Height: | Size: 605 B |
1
resources-icons-53/tap_type.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="53" viewBox="0 -960 960 960" width="53" xmlns="http://www.w3.org/2000/svg"><path d="M445-80q-29 0-56-12t-45-35L127-403l21-23q14-15 34.5-18.5T221-438l99 53v-365q0-12.75 8.675-21.375 8.676-8.625 21.5-8.625 12.825 0 21.325 8.625T380-750v465l-144-77 156 198q10 12 23.76 18 13.76 6 29.24 6h205q38 0 64-26t26-64v-170q0-25.5-17.25-42.75T680-460H460v-60h219.646q50.148 0 85.251 35T800-400v170q0 63-43.5 106.5T650-80H445ZM203-665q-11.074-18.754-17.037-40.492Q180-727.229 180-750.246 180-821 229.725-870.5T350-920q70.55 0 120.275 49.738Q520-820.524 520-749.956q0 22.956-5.963 44.614Q508.074-683.685 497-665l-52-30q7-12 11-26t4-29.478Q460-796 427.882-828q-32.117-32-78-32Q304-860 272-827.917 240-795.833 240-750q0 15 4 29t11 26l-52 30Zm285 335Z" fill="blue" stroke="blue"/></svg>
|
After Width: | Height: | Size: 781 B |
@ -23,4 +23,8 @@
|
|||||||
|
|
||||||
<!-- Best be a public URL in order to work away from your home LAN and have a trusted HTTPS certificate -->
|
<!-- 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>
|
<property id="config_url" type="string"></property>
|
||||||
|
|
||||||
|
<property id="types_representation" type="boolean"></property>
|
||||||
|
|
||||||
|
<property id="menu_alignment" type="boolean"></property>
|
||||||
</properties>
|
</properties>
|
||||||
|
@ -42,4 +42,22 @@
|
|||||||
type="alphaNumeric"
|
type="alphaNumeric"
|
||||||
/>
|
/>
|
||||||
</setting>
|
</setting>
|
||||||
|
|
||||||
|
<setting
|
||||||
|
propertyKey="@Properties.types_representation"
|
||||||
|
title="Representing types with icons (off) or with labels (on)"
|
||||||
|
>
|
||||||
|
<settingConfig
|
||||||
|
type="boolean"
|
||||||
|
/>
|
||||||
|
</setting>
|
||||||
|
|
||||||
|
<setting
|
||||||
|
propertyKey="@Properties.menu_alignment"
|
||||||
|
title="Left (off) or Right (on) Menu Alignment"
|
||||||
|
>
|
||||||
|
<settingConfig
|
||||||
|
type="boolean"
|
||||||
|
/>
|
||||||
|
</setting>
|
||||||
</settings>
|
</settings>
|
||||||
|
@ -30,12 +30,12 @@ using Toybox.Timer;
|
|||||||
const bRadius = 10;
|
const bRadius = 10;
|
||||||
|
|
||||||
class Alert extends WatchUi.View {
|
class Alert extends WatchUi.View {
|
||||||
hidden var mTimer;
|
private var mTimer;
|
||||||
hidden var mTimeout;
|
private var mTimeout;
|
||||||
hidden var mText;
|
private var mText;
|
||||||
hidden var mFont;
|
private var mFont;
|
||||||
hidden var mFgcolor;
|
private var mFgcolor;
|
||||||
hidden var mBgcolor;
|
private var mBgcolor;
|
||||||
|
|
||||||
function initialize(params as Lang.Dictionary) {
|
function initialize(params as Lang.Dictionary) {
|
||||||
View.initialize();
|
View.initialize();
|
||||||
|
@ -26,14 +26,14 @@ using Toybox.WatchUi;
|
|||||||
using Toybox.Communications;
|
using Toybox.Communications;
|
||||||
|
|
||||||
class ErrorView extends ScalableView {
|
class ErrorView extends ScalableView {
|
||||||
hidden const cSettings as Lang.Dictionary = {
|
private const cSettings as Lang.Dictionary = {
|
||||||
:errorIconMargin => 7f
|
:errorIconMargin => 7f
|
||||||
};
|
};
|
||||||
// Vertical spacing between the top of the face and the error icon
|
// Vertical spacing between the top of the face and the error icon
|
||||||
hidden var mErrorIconMargin;
|
private var mErrorIconMargin;
|
||||||
hidden var mText as Lang.String;
|
private var mText as Lang.String;
|
||||||
hidden var mErrorIcon;
|
private var mErrorIcon;
|
||||||
hidden var mTextArea;
|
private var mTextArea;
|
||||||
|
|
||||||
function initialize(text as Lang.String) {
|
function initialize(text as Lang.String) {
|
||||||
ScalableView.initialize();
|
ScalableView.initialize();
|
||||||
|
@ -24,20 +24,20 @@ using Toybox.WatchUi;
|
|||||||
using Toybox.Application.Properties;
|
using Toybox.Application.Properties;
|
||||||
|
|
||||||
class HomeAssistantApp extends Application.AppBase {
|
class HomeAssistantApp extends Application.AppBase {
|
||||||
hidden var mHaMenu;
|
private var mHaMenu;
|
||||||
hidden var strNoApiKey as Lang.String;
|
private var strNoApiKey as Lang.String;
|
||||||
hidden var strNoApiUrl as Lang.String;
|
private var strNoApiUrl as Lang.String;
|
||||||
hidden var strNoConfigUrl as Lang.String;
|
private var strNoConfigUrl as Lang.String;
|
||||||
hidden var strNoPhone as Lang.String;
|
private var strNoPhone as Lang.String;
|
||||||
hidden var strNoInternet as Lang.String;
|
private var strNoInternet as Lang.String;
|
||||||
hidden var strNoResponse as Lang.String;
|
private var strNoResponse as Lang.String;
|
||||||
hidden var strNoMenu as Lang.String;
|
private var strNoMenu as Lang.String;
|
||||||
hidden var strApiFlood as Lang.String;
|
private var strApiFlood as Lang.String;
|
||||||
hidden var strConfigUrlNotFound as Lang.String;
|
private var strConfigUrlNotFound as Lang.String;
|
||||||
hidden var strUnhandledHttpErr as Lang.String;
|
private var strUnhandledHttpErr as Lang.String;
|
||||||
hidden var strTrailingSlashErr as Lang.String;
|
private var strTrailingSlashErr as Lang.String;
|
||||||
hidden var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
|
private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
|
||||||
hidden var mNextItemToUpdate = 0; // Index into the above array
|
private var mNextItemToUpdate = 0; // Index into the above array
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
AppBase.initialize();
|
AppBase.initialize();
|
||||||
@ -67,22 +67,22 @@ class HomeAssistantApp extends Application.AppBase {
|
|||||||
|
|
||||||
if ((Properties.getValue("api_key") as Lang.String).length() == 0) {
|
if ((Properties.getValue("api_key") as Lang.String).length() == 0) {
|
||||||
if (Globals.scDebug) {
|
if (Globals.scDebug) {
|
||||||
System.println("HomeAssistantMenuItem execScript(): No API key in the application settings.");
|
System.println("HomeAssistantApp getInitialView(): No API key in the application settings.");
|
||||||
}
|
}
|
||||||
return [new ErrorView(strNoApiKey + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
return [new ErrorView(strNoApiKey + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||||
} else if (api_url.length() == 0) {
|
} else if (api_url.length() == 0) {
|
||||||
if (Globals.scDebug) {
|
if (Globals.scDebug) {
|
||||||
System.println("HomeAssistantMenuItem execScript(): No API URL in the application settings.");
|
System.println("HomeAssistantApp getInitialView(): No API URL in the application settings.");
|
||||||
}
|
}
|
||||||
return [new ErrorView(strNoApiUrl + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
return [new ErrorView(strNoApiUrl + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||||
} else if (api_url.substring(-1, api_url.length()).equals("/")) {
|
} else if (api_url.substring(-1, api_url.length()).equals("/")) {
|
||||||
if (Globals.scDebug) {
|
if (Globals.scDebug) {
|
||||||
System.println("HomeAssistantMenuItem execScript(): API URL must not have a trailing slash '/'.");
|
System.println("HomeAssistantApp getInitialView(): API URL must not have a trailing slash '/'.");
|
||||||
}
|
}
|
||||||
return [new ErrorView(strTrailingSlashErr + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
return [new ErrorView(strTrailingSlashErr + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||||
} else if ((Properties.getValue("config_url") as Lang.String).length() == 0) {
|
} else if ((Properties.getValue("config_url") as Lang.String).length() == 0) {
|
||||||
if (Globals.scDebug) {
|
if (Globals.scDebug) {
|
||||||
System.println("HomeAssistantMenuItem execScript(): No configuration URL in the application settings.");
|
System.println("HomeAssistantApp getInitialView(): No configuration URL in the application settings.");
|
||||||
}
|
}
|
||||||
return [new ErrorView(strNoConfigUrl + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
return [new ErrorView(strNoConfigUrl + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||||
} else if (! System.getDeviceSettings().phoneConnected) {
|
} else if (! System.getDeviceSettings().phoneConnected) {
|
||||||
|
58
source/HomeAssistantIconMenuItem.mc
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// P A Abbey & J D Abbey, 31 October 2023
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// Menu button that triggers a service.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Toybox.Lang;
|
||||||
|
using Toybox.WatchUi;
|
||||||
|
using Toybox.Graphics;
|
||||||
|
using Toybox.Application.Properties;
|
||||||
|
|
||||||
|
class HomeAssistantIconMenuItem extends WatchUi.IconMenuItem {
|
||||||
|
private var mHomeAssistantService as HomeAssistantService;
|
||||||
|
private var mService as Lang.String;
|
||||||
|
|
||||||
|
function initialize(
|
||||||
|
label as Lang.String or Lang.Symbol,
|
||||||
|
subLabel as Lang.String or Lang.Symbol or Null,
|
||||||
|
identifier as Lang.Object or Null,
|
||||||
|
service as Lang.String or Null,
|
||||||
|
icon as Graphics.BitmapType or WatchUi.Drawable,
|
||||||
|
options as {
|
||||||
|
:alignment as WatchUi.MenuItem.Alignment
|
||||||
|
} or Null,
|
||||||
|
haService as HomeAssistantService
|
||||||
|
) {
|
||||||
|
WatchUi.IconMenuItem.initialize(
|
||||||
|
label,
|
||||||
|
subLabel,
|
||||||
|
identifier,
|
||||||
|
icon,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
mHomeAssistantService = haService;
|
||||||
|
mIdentifier = identifier;
|
||||||
|
mService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
function callService() as Void {
|
||||||
|
mHomeAssistantService.call(mIdentifier as Lang.String, mService);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -24,14 +24,8 @@ using Toybox.Graphics;
|
|||||||
using Toybox.Application.Properties;
|
using Toybox.Application.Properties;
|
||||||
|
|
||||||
class HomeAssistantMenuItem extends WatchUi.MenuItem {
|
class HomeAssistantMenuItem extends WatchUi.MenuItem {
|
||||||
hidden var mApiKey as Lang.String;
|
private var mHomeAssistantService as HomeAssistantService;
|
||||||
hidden var strNoPhone as Lang.String;
|
private var mService as Lang.String;
|
||||||
hidden var strNoInternet as Lang.String;
|
|
||||||
hidden var strNoResponse as Lang.String;
|
|
||||||
hidden var strApiFlood as Lang.String;
|
|
||||||
hidden var strApiUrlNotFound as Lang.String;
|
|
||||||
hidden var strUnhandledHttpErr as Lang.String;
|
|
||||||
hidden var mService as Lang.String;
|
|
||||||
|
|
||||||
function initialize(
|
function initialize(
|
||||||
label as Lang.String or Lang.Symbol,
|
label as Lang.String or Lang.Symbol,
|
||||||
@ -41,142 +35,22 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
|
|||||||
options as {
|
options as {
|
||||||
:alignment as WatchUi.MenuItem.Alignment,
|
:alignment as WatchUi.MenuItem.Alignment,
|
||||||
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
|
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
|
||||||
} or Null
|
} or Null,
|
||||||
|
haService as HomeAssistantService
|
||||||
) {
|
) {
|
||||||
strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
|
||||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
|
||||||
strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
|
||||||
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
|
||||||
strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
|
||||||
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
|
||||||
mApiKey = Properties.getValue("api_key");
|
|
||||||
mService = service;
|
|
||||||
WatchUi.MenuItem.initialize(
|
WatchUi.MenuItem.initialize(
|
||||||
label,
|
label,
|
||||||
subLabel,
|
subLabel,
|
||||||
identifier,
|
identifier,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mHomeAssistantService = haService;
|
||||||
|
mService = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback function after completing the POST request to call a script.
|
function callService() as Void {
|
||||||
//
|
mHomeAssistantService.call(mIdentifier as Lang.String, mService);
|
||||||
function onReturnExecScript(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript() Response Code: " + responseCode);
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript() Response Data: " + data);
|
|
||||||
}
|
|
||||||
if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
|
||||||
}
|
|
||||||
WatchUi.pushView(new ErrorView(strNoPhone + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
|
||||||
} else if (responseCode == Communications.BLE_QUEUE_FULL) {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
|
||||||
}
|
|
||||||
if (!(WatchUi.getCurrentView()[0] instanceof ErrorView)) {
|
|
||||||
// Avoid pushing multiple ErrorViews
|
|
||||||
WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
|
||||||
}
|
|
||||||
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
|
||||||
}
|
|
||||||
WatchUi.pushView(new ErrorView(strNoResponse), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
|
||||||
} else if (responseCode == 404) {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript() Response Code: 404, page not found. Check API URL setting.");
|
|
||||||
}
|
|
||||||
WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
|
||||||
} else if (responseCode == 200) {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript(): Service executed.");
|
|
||||||
}
|
|
||||||
var d = data as Lang.Array;
|
|
||||||
var toast = "Executed";
|
|
||||||
for(var i = 0; i < d.size(); i++) {
|
|
||||||
if ((d[i].get("entity_id") as Lang.String).equals(mIdentifier)) {
|
|
||||||
toast = (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (WatchUi has :showToast) {
|
|
||||||
WatchUi.showToast(toast, null);
|
|
||||||
} else {
|
|
||||||
new Alert({
|
|
||||||
:timeout => Globals.scAlertTimeout,
|
|
||||||
:font => Graphics.FONT_MEDIUM,
|
|
||||||
:text => toast,
|
|
||||||
:fgcolor => Graphics.COLOR_WHITE,
|
|
||||||
:bgcolor => Graphics.COLOR_BLACK
|
|
||||||
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem onReturnExecScript(): Unhandled HTTP response code = " + responseCode);
|
|
||||||
}
|
|
||||||
WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function execScript() as Void {
|
|
||||||
var options = {
|
|
||||||
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
|
||||||
:headers => {
|
|
||||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
|
||||||
"Authorization" => "Bearer " + mApiKey
|
|
||||||
},
|
|
||||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
|
||||||
};
|
|
||||||
if (! System.getDeviceSettings().phoneConnected) {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem execScript(): No Phone connection, skipping API call.");
|
|
||||||
}
|
|
||||||
WatchUi.pushView(new ErrorView(strNoPhone + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
|
||||||
} else if (! System.getDeviceSettings().connectionAvailable) {
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem execScript(): No Internet connection, skipping API call.");
|
|
||||||
}
|
|
||||||
WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
|
||||||
} else {
|
|
||||||
// Updated SDK and got a new error
|
|
||||||
// ERROR: venu: Cannot find symbol ':substring' on type 'PolyType<Null or $.Toybox.Lang.Object>'.
|
|
||||||
var id = mIdentifier as Lang.String;
|
|
||||||
if (mService == null) {
|
|
||||||
var url = (Properties.getValue("api_url") as Lang.String) + "/services/" + id.substring(0, id.find(".")) + "/" + id.substring(id.find(".")+1, null);
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem execScript() URL=" + url);
|
|
||||||
System.println("HomeAssistantMenuItem execScript() mIdentifier=" + mIdentifier);
|
|
||||||
}
|
|
||||||
Communications.makeWebRequest(
|
|
||||||
url,
|
|
||||||
null,
|
|
||||||
options,
|
|
||||||
method(:onReturnExecScript)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
var url = (Properties.getValue("api_url") as Lang.String) + "/services/" + mService.substring(0, mService.find(".")) + "/" + mService.substring(mService.find(".")+1, null);
|
|
||||||
if (Globals.scDebug) {
|
|
||||||
System.println("HomeAssistantMenuItem execScript() URL=" + url);
|
|
||||||
System.println("HomeAssistantMenuItem execScript() mService=" + mService);
|
|
||||||
}
|
|
||||||
Communications.makeWebRequest(
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
"entity_id" => id
|
|
||||||
},
|
|
||||||
options,
|
|
||||||
method(:onReturnExecScript)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (Attention has :vibrate) {
|
|
||||||
Attention.vibrate([
|
|
||||||
new Attention.VibeProfile(50, 100), // On for 100ms
|
|
||||||
new Attention.VibeProfile( 0, 100), // Off for 100ms
|
|
||||||
new Attention.VibeProfile(50, 100) // On for 100ms
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
122
source/HomeAssistantMenuItemFactory.mc
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// P A Abbey & J D Abbey & SomeoneOnEarth, 17 November 2023
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// MenuItems Factory.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Toybox.Application;
|
||||||
|
using Toybox.Lang;
|
||||||
|
using Toybox.WatchUi;
|
||||||
|
|
||||||
|
class HomeAssistantMenuItemFactory {
|
||||||
|
private var mMenuItemOptions as Lang.Dictionary;
|
||||||
|
private var mLabelToggle as Lang.Dictionary;
|
||||||
|
private var strMenuItemTap as Lang.String;
|
||||||
|
private var bRepresentTypesWithLabels as Lang.Boolean;
|
||||||
|
private var mTapTypeIcon as WatchUi.Bitmap;
|
||||||
|
private var mGroupTypeIcon as WatchUi.Bitmap;
|
||||||
|
private var mHomeAssistantService as HomeAssistantService;
|
||||||
|
|
||||||
|
private static var instance;
|
||||||
|
|
||||||
|
private function initialize() {
|
||||||
|
mLabelToggle = {
|
||||||
|
:enabled => WatchUi.loadResource($.Rez.Strings.MenuItemOn) as Lang.String,
|
||||||
|
:disabled => WatchUi.loadResource($.Rez.Strings.MenuItemOff) as Lang.String
|
||||||
|
};
|
||||||
|
bRepresentTypesWithLabels = Application.Properties.getValue("types_representation") as Lang.Boolean;
|
||||||
|
|
||||||
|
var menuItemAlignment = Application.Properties.getValue("menu_alignment") as Lang.Boolean;
|
||||||
|
if(menuItemAlignment){
|
||||||
|
mMenuItemOptions = {
|
||||||
|
:alignment => WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_RIGHT
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
mMenuItemOptions = {
|
||||||
|
:alignment => WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_LEFT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
strMenuItemTap = WatchUi.loadResource($.Rez.Strings.MenuItemTap);
|
||||||
|
mTapTypeIcon = new WatchUi.Bitmap({
|
||||||
|
:rezId => $.Rez.Drawables.TapTypeIcon,
|
||||||
|
:locX => WatchUi.LAYOUT_HALIGN_CENTER,
|
||||||
|
:locY => WatchUi.LAYOUT_VALIGN_CENTER
|
||||||
|
});
|
||||||
|
|
||||||
|
mGroupTypeIcon = new WatchUi.Bitmap({
|
||||||
|
:rezId => $.Rez.Drawables.GroupTypeIcon,
|
||||||
|
:locX => WatchUi.LAYOUT_HALIGN_CENTER,
|
||||||
|
:locY => WatchUi.LAYOUT_VALIGN_CENTER
|
||||||
|
});
|
||||||
|
mHomeAssistantService = new HomeAssistantService();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function create() as HomeAssistantMenuItemFactory {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new HomeAssistantMenuItemFactory();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(label as Lang.String or Lang.Symbol, identifier as Lang.Object or Null) as WatchUi.MenuItem {
|
||||||
|
var subLabel = null;
|
||||||
|
|
||||||
|
if (bRepresentTypesWithLabels == true){
|
||||||
|
subLabel=mLabelToggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HomeAssistantToggleMenuItem(
|
||||||
|
label,
|
||||||
|
subLabel,
|
||||||
|
identifier,
|
||||||
|
false,
|
||||||
|
mMenuItemOptions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tap(label as Lang.String or Lang.Symbol, identifier as Lang.Object or Null, service as Lang.String or Null) as WatchUi.MenuItem {
|
||||||
|
if (bRepresentTypesWithLabels) {
|
||||||
|
return new HomeAssistantMenuItem(
|
||||||
|
label,
|
||||||
|
strMenuItemTap,
|
||||||
|
identifier,
|
||||||
|
service,
|
||||||
|
mMenuItemOptions,
|
||||||
|
mHomeAssistantService
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return new HomeAssistantIconMenuItem(
|
||||||
|
label,
|
||||||
|
null,
|
||||||
|
identifier,
|
||||||
|
service,
|
||||||
|
mTapTypeIcon,
|
||||||
|
mMenuItemOptions,
|
||||||
|
mHomeAssistantService
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function group(definition as Lang.Dictionary) as WatchUi.MenuItem {
|
||||||
|
if (bRepresentTypesWithLabels) {
|
||||||
|
return new HomeAssistantViewMenuItem(definition);
|
||||||
|
} else {
|
||||||
|
return new HomeAssistantViewIconMenuItem(definition, mGroupTypeIcon, mMenuItemOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
150
source/HomeAssistantService.mc
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// P A Abbey & J D Abbey & SomeoneOnEarth, 19 November 2023
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// Calling a Home Assistant Service.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Toybox.Lang;
|
||||||
|
using Toybox.WatchUi;
|
||||||
|
using Toybox.Graphics;
|
||||||
|
using Toybox.Application.Properties;
|
||||||
|
|
||||||
|
class HomeAssistantService {
|
||||||
|
private var mApiKey as Lang.String;
|
||||||
|
private var strNoPhone as Lang.String;
|
||||||
|
private var strNoInternet as Lang.String;
|
||||||
|
private var strNoResponse as Lang.String;
|
||||||
|
private var strApiFlood as Lang.String;
|
||||||
|
private var strApiUrlNotFound as Lang.String;
|
||||||
|
private var strUnhandledHttpErr as Lang.String;
|
||||||
|
|
||||||
|
function initialize() {
|
||||||
|
strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||||
|
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||||
|
strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||||
|
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||||
|
strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
||||||
|
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||||
|
mApiKey = Properties.getValue("api_key");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback function after completing the POST request to call a service.
|
||||||
|
//
|
||||||
|
function onReturnCall(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String, context as Lang.Object) as Void {
|
||||||
|
var identifier = context as Lang.String;
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService onReturnCall() Response Code: " + responseCode);
|
||||||
|
System.println("HomeAssistantService onReturnCall() Response Data: " + data);
|
||||||
|
}
|
||||||
|
if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService onReturnCall() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||||
|
}
|
||||||
|
WatchUi.pushView(new ErrorView(strNoPhone + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||||
|
} else if (responseCode == Communications.BLE_QUEUE_FULL) {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService onReturnCall() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||||
|
}
|
||||||
|
if (!(WatchUi.getCurrentView()[0] instanceof ErrorView)) {
|
||||||
|
// Avoid pushing multiple ErrorViews
|
||||||
|
WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||||
|
}
|
||||||
|
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService onReturnCall() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||||
|
}
|
||||||
|
WatchUi.pushView(new ErrorView(strNoResponse), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||||
|
} else if (responseCode == 404) {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService onReturnCall() Response Code: 404, page not found. Check API URL setting.");
|
||||||
|
}
|
||||||
|
WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||||
|
} else if (responseCode == 200) {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService onReturnCall(): Service executed.");
|
||||||
|
}
|
||||||
|
var d = data as Lang.Array;
|
||||||
|
var toast = "Executed";
|
||||||
|
for(var i = 0; i < d.size(); i++) {
|
||||||
|
if ((d[i].get("entity_id") as Lang.String).equals(identifier)) {
|
||||||
|
toast = (d[i].get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (WatchUi has :showToast) {
|
||||||
|
WatchUi.showToast(toast, null);
|
||||||
|
} else {
|
||||||
|
new Alert({
|
||||||
|
:timeout => Globals.scAlertTimeout,
|
||||||
|
:font => Graphics.FONT_MEDIUM,
|
||||||
|
:text => toast,
|
||||||
|
:fgcolor => Graphics.COLOR_WHITE,
|
||||||
|
:bgcolor => Graphics.COLOR_BLACK
|
||||||
|
}).pushView(WatchUi.SLIDE_IMMEDIATE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService onReturnCall(): Unhandled HTTP response code = " + responseCode);
|
||||||
|
}
|
||||||
|
WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function call(identifier as Lang.String, service as Lang.String) as Void {
|
||||||
|
var options = {
|
||||||
|
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
||||||
|
:headers => {
|
||||||
|
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
||||||
|
"Authorization" => "Bearer " + mApiKey
|
||||||
|
},
|
||||||
|
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON,
|
||||||
|
:context => identifier
|
||||||
|
};
|
||||||
|
if (! System.getDeviceSettings().phoneConnected) {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService call(): No Phone connection, skipping API call.");
|
||||||
|
}
|
||||||
|
WatchUi.pushView(new ErrorView(strNoPhone + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||||
|
} else if (! System.getDeviceSettings().connectionAvailable) {
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService call(): No Internet connection, skipping API call.");
|
||||||
|
}
|
||||||
|
WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
|
||||||
|
} else {
|
||||||
|
var url = (Properties.getValue("api_url") as Lang.String) + "/services/" + service.substring(0, service.find(".")) + "/" + service.substring(service.find(".")+1, null);
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("HomeAssistantService call() URL=" + url);
|
||||||
|
System.println("HomeAssistantService call() service=" + service);
|
||||||
|
}
|
||||||
|
Communications.makeWebRequest(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
"entity_id" => identifier
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
method(:onReturnCall)
|
||||||
|
);
|
||||||
|
if (Attention has :vibrate) {
|
||||||
|
Attention.vibrate([
|
||||||
|
new Attention.VibeProfile(50, 100), // On for 100ms
|
||||||
|
new Attention.VibeProfile( 0, 100), // Off for 100ms
|
||||||
|
new Attention.VibeProfile(50, 100) // On for 100ms
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,13 +25,13 @@ using Toybox.Application.Properties;
|
|||||||
using Toybox.Timer;
|
using Toybox.Timer;
|
||||||
|
|
||||||
class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||||
hidden var mApiKey as Lang.String;
|
private var mApiKey as Lang.String;
|
||||||
hidden var strNoPhone as Lang.String;
|
private var strNoPhone as Lang.String;
|
||||||
hidden var strNoInternet as Lang.String;
|
private var strNoInternet as Lang.String;
|
||||||
hidden var strNoResponse as Lang.String;
|
private var strNoResponse as Lang.String;
|
||||||
hidden var strApiFlood as Lang.String;
|
private var strApiFlood as Lang.String;
|
||||||
hidden var strApiUrlNotFound as Lang.String;
|
private var strApiUrlNotFound as Lang.String;
|
||||||
hidden var strUnhandledHttpErr as Lang.String;
|
private var strUnhandledHttpErr as Lang.String;
|
||||||
|
|
||||||
function initialize(
|
function initialize(
|
||||||
label as Lang.String or Lang.Symbol,
|
label as Lang.String or Lang.Symbol,
|
||||||
@ -131,7 +131,6 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
|||||||
if (keepUpdating) {
|
if (keepUpdating) {
|
||||||
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
|
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
|
||||||
getApp().updateNextMenuItem();
|
getApp().updateNextMenuItem();
|
||||||
System.println("HomeAssistantToggleMenuItem onReturnGetState(): Updated " + mIdentifier);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,15 +18,15 @@
|
|||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Toybox.Application;
|
||||||
using Toybox.Lang;
|
using Toybox.Lang;
|
||||||
using Toybox.Graphics;
|
using Toybox.Graphics;
|
||||||
using Toybox.WatchUi;
|
using Toybox.WatchUi;
|
||||||
|
|
||||||
class HomeAssistantView extends WatchUi.Menu2 {
|
class HomeAssistantView extends WatchUi.Menu2 {
|
||||||
hidden var strMenuItemTap as Lang.String;
|
|
||||||
// List of items that need to have their status updated periodically
|
// List of items that need to have their status updated periodically
|
||||||
hidden var mListToggleItems = [];
|
private var mListToggleItems = [];
|
||||||
hidden var mListMenuItems = [];
|
private var mListMenuItems = [];
|
||||||
|
|
||||||
function initialize(
|
function initialize(
|
||||||
definition as Lang.Dictionary,
|
definition as Lang.Dictionary,
|
||||||
@ -36,11 +36,6 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
|||||||
:theme as WatchUi.MenuTheme or Null
|
:theme as WatchUi.MenuTheme or Null
|
||||||
} or Null
|
} or Null
|
||||||
) {
|
) {
|
||||||
strMenuItemTap = WatchUi.loadResource($.Rez.Strings.MenuItemTap);
|
|
||||||
var toggle_obj = {
|
|
||||||
:enabled => WatchUi.loadResource($.Rez.Strings.MenuItemOn) as Lang.String,
|
|
||||||
:disabled => WatchUi.loadResource($.Rez.Strings.MenuItemOff) as Lang.String
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
options = {
|
options = {
|
||||||
@ -59,27 +54,13 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
|||||||
var service = items[i].get("service") as Lang.String or Null;
|
var service = items[i].get("service") as Lang.String or Null;
|
||||||
if (type != null && name != null && entity != null) {
|
if (type != null && name != null && entity != null) {
|
||||||
if (type.equals("toggle")) {
|
if (type.equals("toggle")) {
|
||||||
var item = new HomeAssistantToggleMenuItem(
|
var item = HomeAssistantMenuItemFactory.create().toggle(name, entity);
|
||||||
name,
|
|
||||||
toggle_obj,
|
|
||||||
entity,
|
|
||||||
false,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
addItem(item);
|
addItem(item);
|
||||||
mListToggleItems.add(item);
|
mListToggleItems.add(item);
|
||||||
} else if (type.equals("tap") && service != null) {
|
} else if (type.equals("tap") && service != null) {
|
||||||
addItem(
|
addItem( HomeAssistantMenuItemFactory.create().tap(name, entity, service));
|
||||||
new HomeAssistantMenuItem(
|
|
||||||
name,
|
|
||||||
strMenuItemTap,
|
|
||||||
entity,
|
|
||||||
service,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else if (type.equals("group")) {
|
} else if (type.equals("group")) {
|
||||||
var item = new HomeAssistantViewMenuItem(items[i]);
|
var item = HomeAssistantMenuItemFactory.create().group(items[i]);
|
||||||
addItem(item);
|
addItem(item);
|
||||||
mListMenuItems.add(item);
|
mListMenuItems.add(item);
|
||||||
}
|
}
|
||||||
@ -89,10 +70,15 @@ class HomeAssistantView extends WatchUi.Menu2 {
|
|||||||
|
|
||||||
function getItemsToUpdate() as Lang.Array<HomeAssistantToggleMenuItem> {
|
function getItemsToUpdate() as Lang.Array<HomeAssistantToggleMenuItem> {
|
||||||
var fullList = [];
|
var fullList = [];
|
||||||
var lmi = mListMenuItems as Lang.Array<HomeAssistantViewMenuItem>;
|
|
||||||
for(var i = 0; i < lmi.size(); i++) {
|
var lmi = mListMenuItems as Lang.Array<WatchUi.MenuItem>;
|
||||||
fullList.addAll(lmi[i].getMenuView().getItemsToUpdate());
|
for(var i = 0; i < mListMenuItems.size(); i++) {
|
||||||
|
var item = lmi[i];
|
||||||
|
if (item instanceof HomeAssistantViewMenuItem || item instanceof HomeAssistantViewIconMenuItem) {
|
||||||
|
fullList.addAll(item.getMenuView().getItemsToUpdate());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return fullList.addAll(mListToggleItems);
|
return fullList.addAll(mListToggleItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +110,13 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
|
|||||||
if (Globals.scDebug) {
|
if (Globals.scDebug) {
|
||||||
System.println(haItem.getLabel() + " " + haItem.getId());
|
System.println(haItem.getLabel() + " " + haItem.getId());
|
||||||
}
|
}
|
||||||
haItem.execScript();
|
haItem.callService();
|
||||||
|
} else if (item instanceof HomeAssistantIconMenuItem) {
|
||||||
|
var haItem = item as HomeAssistantIconMenuItem;
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println(haItem.getLabel() + " " + haItem.getId());
|
||||||
|
}
|
||||||
|
haItem.callService();
|
||||||
} else if (item instanceof HomeAssistantViewMenuItem) {
|
} else if (item instanceof HomeAssistantViewMenuItem) {
|
||||||
var haMenuItem = item as HomeAssistantViewMenuItem;
|
var haMenuItem = item as HomeAssistantViewMenuItem;
|
||||||
if (Globals.scDebug) {
|
if (Globals.scDebug) {
|
||||||
@ -132,6 +124,13 @@ class HomeAssistantViewDelegate extends WatchUi.Menu2InputDelegate {
|
|||||||
}
|
}
|
||||||
// No delegate state to be amended, so re-use 'self'.
|
// No delegate state to be amended, so re-use 'self'.
|
||||||
WatchUi.pushView(haMenuItem.getMenuView(), self, WatchUi.SLIDE_LEFT);
|
WatchUi.pushView(haMenuItem.getMenuView(), self, WatchUi.SLIDE_LEFT);
|
||||||
|
} else if (item instanceof HomeAssistantViewIconMenuItem) {
|
||||||
|
var haMenuItem = item as HomeAssistantViewIconMenuItem;
|
||||||
|
if (Globals.scDebug) {
|
||||||
|
System.println("IconMenu: " + haMenuItem.getLabel() + " " + haMenuItem.getId());
|
||||||
|
}
|
||||||
|
// No delegate state to be amended, so re-use 'self'.
|
||||||
|
WatchUi.pushView(haMenuItem.getMenuView(), self, WatchUi.SLIDE_LEFT);
|
||||||
} else {
|
} else {
|
||||||
if (Globals.scDebug) {
|
if (Globals.scDebug) {
|
||||||
System.println(item.getLabel() + " " + item.getId());
|
System.println(item.getLabel() + " " + item.getId());
|
||||||
|
48
source/HomeAssistantViewIconMenuItem.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.
|
||||||
|
//
|
||||||
|
// P A Abbey & J D Abbey & SomeoneOnEarth, 16 November 2023
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// Menu button with an icon that opens a sub-menu.
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Toybox.Lang;
|
||||||
|
using Toybox.WatchUi;
|
||||||
|
|
||||||
|
class HomeAssistantViewIconMenuItem extends WatchUi.IconMenuItem {
|
||||||
|
private var mMenu as HomeAssistantView;
|
||||||
|
|
||||||
|
function initialize(definition as Lang.Dictionary, icon as WatchUi.Drawable, options as {
|
||||||
|
:alignment as WatchUi.MenuItem.Alignment
|
||||||
|
} or Null) {
|
||||||
|
var label = definition.get("name") as Lang.String;
|
||||||
|
var identifier = definition.get("entity") as Lang.String;
|
||||||
|
|
||||||
|
WatchUi.IconMenuItem.initialize(
|
||||||
|
label,
|
||||||
|
null,
|
||||||
|
identifier,
|
||||||
|
icon,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
mMenu = new HomeAssistantView(definition, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMenuView() as HomeAssistantView {
|
||||||
|
return mMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,7 +22,7 @@ using Toybox.Lang;
|
|||||||
using Toybox.WatchUi;
|
using Toybox.WatchUi;
|
||||||
|
|
||||||
class HomeAssistantViewMenuItem extends WatchUi.MenuItem {
|
class HomeAssistantViewMenuItem extends WatchUi.MenuItem {
|
||||||
hidden var mMenu as HomeAssistantView;
|
private var mMenu as HomeAssistantView;
|
||||||
|
|
||||||
function initialize(definition as Lang.Dictionary) {
|
function initialize(definition as Lang.Dictionary) {
|
||||||
// definitions.get(...) are Strings here as they have been checked by HomeAssistantView first
|
// definitions.get(...) are Strings here as they have been checked by HomeAssistantView first
|
||||||
|
@ -23,7 +23,7 @@ using Toybox.WatchUi;
|
|||||||
using Toybox.Math;
|
using Toybox.Math;
|
||||||
|
|
||||||
class ScalableView extends WatchUi.View {
|
class ScalableView extends WatchUi.View {
|
||||||
hidden var mScreenWidth;
|
private var mScreenWidth;
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
View.initialize();
|
View.initialize();
|
||||||
|