This is a great start. It’s pretty much exactly what I was thinking. You may or may not want the mediaList
property in the end. It will depend on what you do with list items themselves.
You get a little off track here. You’re already inside a list. That’s what the list card does for you. You don’t want to nest lists like this, you just want to start adding list items directly to the list card’s list. So the list item itself should be the direct child of the repeater.
The f7-list-item
has gotten you into a little bit of trouble here. You don’t see the clock icon in your list because the f7 component doesn’t take an icon
property, that’s added in by the oh version, the oh-list-item
. It also looks like you tried to add an action to the list item, but that didn’t work for the same reason. Actions are not an f7 feature they are an oh specific feature so they will only work with some oh elements. So here, it seems you really want to use the oh-list-item
instead of the f7-list-item
.
Once you can add the action directly to the oh-list-item
you probably won’t even need the button any more, but if you’d rather have the action isolated to the button area instead of the entire list item then you can still do this, you’ll just want to use the after
slot instead of the content
slot. That will give you much better visual results.
As for the time picker widget, the sort of expression you want in the disabled property is a slightly tricky one. There are several issues with this:
and some of them are the reason that you are getting the strange behavior with the numbers.
- You don’t need the ternary statement here. The ternary syntax
(test) ? return value if true : return value if false
should be used when you need expression results that are other than true
and false
. But, only needs a boolean value, so you just need the test part which, by definition returns a true or false value.
Number.parseInt('23')
is necessary. That just converts the string literal '23'
into a numeric type, but you can use directly use 23
instead which is a numeric type by default. You see parseInt or parseFloat applied often in widget expressions, but that’s because the state of an item is always returned as a string, even if it is a numerical item. In older OH versions that was the only return option for items, so most numerical item states need to be cast to a number type. If you’re just using, numbers, just type the number.
- The last issue is with the test expression itself. You’ve followed the standard suggestion to test that the variable of interest is defined or use a backup default value, which is good. The problem is that your variable can also hold a falsey value :
0
. When you roll the number down to 0, that counts as a false value so (vars.hours || Number.parseInt(items[props.item].state.split(':')[0]))
returns the item state instead of 0.
There are a few different ways to fix this issue. If you are on a new enough version of OH (snapshot from within the last few weeks, or the new milestone) then you can use the new oh-context
component to define your variables with default values. The avoids that entire problem with the undefined variable test and your disabled expression would just be:
disabled: =vars.hours <= 0
If you want this widget to be usable for older versions of OH then you do still have to wrestle the possibility of undefined variables so you need to test for that explicitly instead of using the OR
shortcut. This is where you can use the ternary expression because you want (if hours variable is not undefined) ? return hours variable : return item state
and then that return value is used in the numerical comparison.
disabled: =((vars.hours !== undefined)?(vars.hours):(Number.parseInt(items[props.item].state.split(':')[0]))) <= 0
That will mostly work, but we’re going to have revise it again in just a moment because of another version of the same 0
issue.
If you run with that disabled expression and decrease the hour variable, when you get to 1 and then decrease again, instead of 0 you’re going to get false
or -
or something like that. Why? because, again, 0
is a falsey value so when your decrease button calculates the value to send and gets 0 the yaml interprets any false value as that key not existing. So instead of 0 there’s no variable value sent.
There’s no great way around this because it’s just a combination of how yaml works and how the OH expressions work. What I usually do is actually convert the variable values to strings by appending .toString()
.
But, of course, if you do that, then in any area where you want to do a calculation or a test with the variable, you need to reconvert it back into a number. So going back to that previous solution as one example, we can just move parseInt
from around the item state to around the entire ternary expression because both the possible return values are strings:
disabled: =Number.parseInt((vars.hours !== undefined)?(vars.hours):(items[props.item].state.split(':')[0])) <= 0