[OH3] Main UI - New „main_widget“ - development and testing [deprecated]

Yes, thats what I mean.

Ah, some kind of nested flex boxes…

I tried it - but all is showing in one Line:

image

uid: main_widget_RadiatorControl_Card1DEV
tags: []
props:
  parameters:
    - context: item
      description: Temperature Equipment Group
      label: Temperature Equipment Group
      name: groupItem
      required: false
      type: TEXT
timestamp: Oct 3, 2022, 11:32:46 AM
component: f7-block
config:
  style:
    padding: 0px
    border-radius: var(--f7-card-expandable-border-radius)
    #box-shadow: 5px 5px 15px 1px rgba(0,0,0,0.05)
    background: RGB(247, 247, 247)
slots:
  default:
    - component: f7-block
      config:
        style:
          height: 60px
          background: "#15B4B7"
          display: flex
          flex-direction: row
          align-items: center
          
      slots:
        default:
          - component: oh-icon
            config:
              icon: iconify:ion:flame-sharp
              width: 40px
              style:
                color: rgb(106,106,106)  
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: column
            slots:
              default:                
                - component: Label
                  config:
                    text: "Label black"
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex-direction: row                   
                  slots:
                    default:                
                      - component: Label
                        config:
                          text: "Label grey"
                      - component: Label
                        config:
                          text: "Label red"    
    

Could you please have a look again?

Set the column flex container’s flex-wrap to nowrap.

YEAH - you made my day.

Where did you learn all this? I read several tutorials, articles and of course the css flex box guide you mentioned a few weeks ago - but I am still struggling with it…

Honestly, I had only the most basic experience with css and javascript until a couple years ago when OH3 came out. I set myself a couple of very complex widget tasks (not unlike this project here) and spent many (occasionally frustrating) hours working those out to my satisfaction which required learning from thee examples in these forums, many different reference web pages, a healthy does of StackExchange, etc. Since then, just answering questions here in the forum has helped me continue to build on that.

Edit: And don’t think I don’t hit my own blocks still too. Especially when trying to get alignment in f7-list-items correct. That stuff drives me bonkers.

1 Like

i understand, so you use filtering by string but you split fan items in different model property. nice idea!

It is the same methods like the mode item in RadiatorControl.
If displayState is set (translated values) the those are shown, otherwise state is shown.
Opening the options menu will always show option labels.

Yes i see :blush: i have seen that when using repeaters, visible options on item state need a page refresh to be applied. Can you make a quick test about this ?

That happened to me in the first version of the refactored RadiatorControl.
I solved it by using

items[loop.item.name].state
1 Like

Glad to hear that you are still learning too :wink:

I got the header example work but now I am struggling with the content part :wink:

Could you give me a hint why this flex example does not put the two arrow-buttons next to each other - even thought I use flex-direction: row?

At the moment they are like in a column.

image

uid: main_widget_RadiatorControl_Card1
tags: []
props:
  parameters:
    - context: item
      description: Temperature Equipment Group
      label: Temperature Equipment Group
      name: groupItem
      required: false
      type: TEXT
timestamp: Oct 3, 2022, 8:50:20 PM
component: f7-block
config:
  style:
    padding: 0px
    border-top-left-radius: var(--f7-card-expandable-border-radius)
    border-top-right-radius: var(--f7-card-expandable-border-radius)
    border-bottom-left-radius: var(--f7-card-expandable-border-radius)
    border-bottom-right-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 15px 1px rgba(0,0,0,0.05)
    background: RGB(247, 247, 247)
slots:
  default:

    - component: f7-block
      config:
        style:
          display: flex
          flex-direction: row
          align-items: center
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              for: tempItem
              sourceType: itemsWithTags
              itemTags: Measurement,Temperature
              filter: "(loop.tempItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
            slots:
              default:
                - component: oh-trend
                  config:
                    trendItem: =loop.tempItem.name
                    trendSampling: 5
                    trendGradient:
                      - red
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: row
                justify-content: flex-end
                align-self: flex-end
            slots:
              default:
                - component: oh-button
                  config:
                    iconF7: arrow_up_circle
                    iconColor: RGB(231, 66, 57)
                    iconSize: 35
                    action: command
                    actionItem: =loop.setpointItem.name
                    actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) + 0.5
                    style:
                      height: 35px
                      background: transparent
                      z-index: 98
                      display: flex
                      flex-direction: row
                - component: oh-button
                  config:
                    iconF7: arrow_down_circle
                    iconColor: RGB(231, 66, 57)
                    iconSize: 35
                    action: command
                    actionItem: =loop.setpointItem.name
                    actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) - 0.5
                    style:
                      height: 35px
                      background: transparent
                      z-index: 98

Same as last time. The buttons are just wrapping.

Flex-box doesn’t guarantee that the items are arranged in the defined direction. It tries to do the best job it can spacing them out given the size and shape of the container. If your card is restrictive in width, then the trendline takes up most of the space and the flex container for the buttons gets squeezed into a narrow space. The container realizes it doesn’t have enough room for both buttons side by side, so it wraps the second button down onto a second row.
image

If the card has plenty of room then even with the trendline in place the flex container can be wide enough to place both buttons side by side:
image

The only way to ensure that the flex box will not wrap items down onto another row is to set flex-wrap: nowrap. Then, even if the card gets very small, the trendline will shrink instead because the flex-box will make sure it is wide enough to hold both buttons side by side.
image

2 Likes

@hmerk - I’m sorry I didn’t mean to cause offence- I was posing a question not a challenge- I am a learner driver with openHAB and didn’t see the relationship between metadata and the semantic model

I apologise if I have upset you it wasn’t my intention- I am excited to see the progress every day on this project and if I need to change sone wrongly configured things my end that’s fine with me

1 Like

No worries, you did not upset me :wink:

1 Like

Hey @hmerk,

would you have a look?

I tried to do it generic way…

uid: main_widget_RadiatorControl_Card
tags: []
props:
  parameters:
    - context: item
      description: Temperature Equipment Group
      label: Temperature Equipment Group
      name: groupItem
      required: false
      type: TEXT
timestamp: Oct 3, 2022, 8:50:20 PM
component: f7-block
config:
  style:
    padding: 5px
    border-top-left-radius: var(--f7-card-expandable-border-radius)
    border-top-right-radius: var(--f7-card-expandable-border-radius)
    border-bottom-left-radius: var(--f7-card-expandable-border-radius)
    border-bottom-right-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 15px 1px rgba(0,0,0,0.05)
    background: RGB(247, 247, 247)
slots:
  default:
    - component: f7-block
      config:
        style:
          height: 60px
          background: "#15B4B7"
          display: flex
          flex-direction: row
          align-items: center
          border-top-left-radius: var(--f7-card-expandable-border-radius)
          border-top-right-radius: var(--f7-card-expandable-border-radius)
          box-shadow: 5px 5px 15px 1px rgba(0,0,0,0.05)
      slots:
        default:
          - component: oh-icon
            config:
              icon: iconify:ion:flame-sharp
              width: 40px
              style:
                color: rgb(106,106,106)
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: column
                flex-wrap: nowrap
            slots:
              default:
                - component: Label
                  config:
                    text: Device Title
                    style:
                      padding-top: 10px
                      font-weight: 200
                      font-size: 14px
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex-direction: row
                  slots:
                    default:
                      - component: oh-repeater
                        config:
                          fetchMetadata: semantics,metadata,listWidget
                          for: tempItem
                          sourceType: itemsWithTags
                          itemTags: Measurement,Temperature
                          filter: "(loop.tempItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                text: =items[loop.tempItem.name].state
                                style:
                                  font-weight: 500
                                  justify-content: flex-end
                                  background-color: "#6a6a6a"
                                  color: white
                      - component: oh-repeater
                        config:
                          fetchMetadata: semantics,metadata,listWidget
                          for: setpointItem
                          sourceType: itemsWithTags
                          itemTags: Setpoint,Temperature
                          filter: "(loop.setpointItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                text: =items[loop.setpointItem.name].state
                                style:
                                  color: red
                                  background: none
                                  font-weight: 500
    - component: f7-block
      config:
        style:
          display: flex
          flex-direction: row
          align-items: center
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              for: tempItem
              sourceType: itemsWithTags
              itemTags: Measurement,Temperature
              filter: "(loop.tempItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
            slots:
              default:
                - component: oh-trend
                  config:
                    trendItem: =loop.tempItem.name
                    trendSampling: 5
                    trendGradient:
                      - red
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: row
                justify-content: flex-end
                align-self: flex-end
                flex-wrap: nowrap
                
            slots:
              default:
                - component: oh-button
                  config:
                    iconF7: arrow_up_circle
                    iconColor: RGB(231, 66, 57)
                    iconSize: 35
                    action: command
                    actionItem: =loop.setpointItem.name
                    actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) + 0.5
                    style:
                      height: 35px
                      background: transparent
                      z-index: 98
                      display: flex
                      flex-direction: row
                      
                - component: oh-button
                  config:
                    iconF7: arrow_down_circle
                    iconColor: RGB(231, 66, 57)
                    iconSize: 35
                    action: command
                    actionItem: =loop.setpointItem.name
                    actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) - 0.5
                    style:
                      height: 35px
                      background: transparent
                      z-index: 98
    - component: f7-block
      config:
        style:
          height: 50px
          background: RGB(242, 242, 242)
          border-radius: 0 0 var(--f7-card-expandable-border-radius) var(--f7-card-expandable-border-radius)
          --f7-card-footer-border-color: transparent
          display: flex
          flex-direction: row
          align-items: center
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              for: modeItem
              sourceType: itemsWithTags
              itemTags: Control,Temperature
              filter: '((loop.modeItem.groupNames.indexOf(props.groupItem) >= 0) && (loop.modeItem.type=="String")) ? true : false'
            slots:
              default:
                - component: f7-block
                  config:
                    style:
                      display: flex
                      flex-direction: row
                      align-items: center
                  slots:
                    default:
                      - component: oh-link
                        config:
                          action: options
                          actionItem: =loop.modeItem.name
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                text: "=items[loop.modeItem.name].displayState ? items[loop.modeItem.name].displayState : items.items[loop.modeItem.name].state"



Of course, I will try and give feedback.

@Nic0205 @Dimitris

Here is a first version of the HVAC (AC) card following Nic’s new template :
image

image

image

Controls and trend are only shown when switched on and following the color scheme.

Widget code:

uid: main_widget_HVAC_Card
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: Title
      required: false
      type: TEXT
    - context: item
      description: HVAC Equipment Group
      label: HVAC Equipment Group
      name: groupItem
      required: false
      type: TEXT
    - context: item
      description: HVAC Power Item
      label: HVAC Power Item
      name: powerItem
      required: false
      type: TEXT
    - context: item
      description: HVAC Mode Item
      label: HVAC Mode Item
      name: modeItem
      required: false
      type: TEXT
timestamp: Oct 4, 2022, 3:26:58 PM
component: f7-block
config:
  style:
    padding: 0px
    border-top-left-radius: var(--f7-card-expandable-border-radius)
    border-top-right-radius: var(--f7-card-expandable-border-radius)
    border-bottom-left-radius: var(--f7-card-expandable-border-radius)
    border-bottom-right-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 15px 1px rgba(0,0,0,0.05)
    background: RGB(247, 247, 247)
slots:
  default:
    - component: f7-block
      config:
        style:
          height: 60px
          background: RGB(247, 247, 247)
          display: flex
          flex-direction: row
          align-items: center
      slots:
        default:
          - component: oh-icon
            config:
              icon: iconify:iconoir:air-conditioner
              width: 40px
              style:
                color: rgb(106,106,106)
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: column
                flex-wrap: nowrap
            slots:
              default:
                - component: Label
                  config:
                    text: =props.Title
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex-direction: row
                  slots:
                    default:
                      - component: oh-repeater
                        config:
                          fetchMetadata: semantics,metadata,listWidget
                          for: tempItem
                          sourceType: itemsWithTags
                          itemTags: Measurement,Temperature
                          filter: "(loop.tempItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                text: =items[loop.tempItem.name].state
                                style:
                                  font-weight: 500
                                  justify-content: flex-end
                      - component: oh-repeater
                        config:
                          fetchMetadata: semantics,metadata,listWidget
                          for: setpointItem
                          sourceType: itemsWithTags
                          itemTags: Setpoint,Temperature
                          filter: "(loop.setpointItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
                        slots:
                          default:
                            - component: f7-chip
                              config:
                                text: =items[loop.setpointItem.name].state
                                style:
                                  color: '=(items[props.modeItem].state=="COOL") ? "#15B4B7" : (items[props.modeItem].state=="HEAT") ? "#E74239" : (items[props.modeItem].state=="DRY") ? "#E7D200" : "gray"'
                                  background: none
                                  font-weight: 500
                      - component: oh-toggle
                        config:
                          item: =props.powerItem
                          style:
                            margin-left: 150px
                            --f7-toggle-active-color: =(items[props.modeItem].state=="COOL")?"#15B4B7":(items[props.modeItem].state=="HEAT")?"#E74239":(items[props.modeItem].state=="DRY")?"#E7D200":"gray"
                            --f7-toggle-inactive-color: gray
    - component: f7-block
      config:
        style:
          display: flex
          flex-direction: row
          align-items: center
        visible: =items[props.powerItem].state=="ON"
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              for: tempItem
              sourceType: itemsWithTags
              itemTags: Measurement,Temperature
              filter: "(loop.tempItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
            slots:
              default:
                - component: oh-trend
                  config:
                    trendItem: =loop.tempItem.name
                    trendSampling: 5
                    trendGradient: =[(items[props.modeItem].state=='COOL')?('#15B4B7'):(items[props.modeItem].state=='HEAT')?('#E74239'):(items[props.modeItem].state=='DRY')?('#E7D200'):('gray'),('gray')]
          - component: f7-row
            config:
              style:
                display: flex
                flex-direction: row
                flex-wrap: nowrap
                justify-content: flex-end
                align-self: flex-end
            slots:
              default:
                - component: oh-link
                  config:
                    action: command
                    actionItem: =loop.setpointItem.name
                    actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) + 0.5
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          icon: f7:arrow_up_circle
                          style:
                            color: '=(items[props.modeItem].state=="COOL") ? "#15B4B7" : (items[props.modeItem].state=="HEAT") ? "#E74239" : (items[props.modeItem].state=="DRY") ? "#E7D200" : "gray"'
                          width: 35px
                - component: oh-link
                  config:
                    action: command
                    actionItem: =loop.setpointItem.name
                    actionCommand: =Number(items[loop.setpointItem.name].state.split(' ')[0]) 1 0.5
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          icon: f7:arrow_down_circle
                          style:
                            margin-left: 20px
                            color: '=(items[props.modeItem].state=="COOL") ? "#15B4B7" : (items[props.modeItem].state=="HEAT") ? "#E74239" : (items[props.modeItem].state=="DRY") ? "#E7D200" : "gray"'
                          width: 35px
    - component: f7-block
      config:
        style:
          height: 50px
          background: RGB(242, 242, 242)
          border-radius: 0 0 var(--f7-card-expandable-border-radius) var(--f7-card-expandable-border-radius)
          --f7-card-footer-border-color: transparent
          display: flex
          flex-direction: row
          flex-wrap: nowrap
          align-items: center
        visible: =items[props.powerItem].state=="ON"
      slots:
        default:
          - component: oh-link
            config:
              action: command
              actionItem: =props.modeItem
              actionCommand: COOL
            slots:
              default:
                - component: oh-icon
                  config:
                    icon: iconify:ion:snow
                    color: '=(items[props.modeItem].state=="COOL") ? "#15B4B7" : "gray"'
                    width: 25px
          - component: oh-link
            config:
              action: command
              actionItem: =props.modeItem
              actionCommand: HEAT
              style:
                margin-left: 25px
            slots:
              default:
                - component: oh-icon
                  config:
                    icon: iconify:ion:flame-sharp
                    color: '=(items[props.modeItem].state=="HEAT") ? "#E74239" : "gray"'
                    width: 25px
          - component: oh-link
            config:
              action: command
              actionItem: =props.modeItem
              actionCommand: DRY
              style:
                margin-left: 25px
            slots:
              default:
                - component: oh-icon
                  config:
                    icon: iconify:material-symbols:cool-to-dry-rounded
                    color: '=(items[props.modeItem].state=="DRY") ? "#E7D200" : "gray"'
                    width: 25px
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              for: fanspeedItem
              sourceType: itemsWithTags
              itemTags: Control,Wind
              filter: "(loop.fanspeedItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
            slots:
              default:
                - component: oh-link
                  config:
                    action: options
                    actionItem: =loop.fanspeedItem.name
                    style:
                      margin-left: 120px
                  slots:
                    default:
                      - component: f7-chip
                        config:
                          text: "=items[loop.fanspeedItem.name].displayState ? items[loop.fanspeedItem.name].displayState : items[loop.fanspeedItem.name].state"
                      - component: oh-icon
                        config:
                          icon: iconify:material-symbols:mode-fan
                          color: gray
                          width: 25px
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              for: vanesItem
              sourceType: itemsWithTags
              itemTags: Control,Opening
              filter: "(loop.vanesItem.groupNames.indexOf(props.groupItem) >= 0) ? true : false"
            slots:
              default:
                - component: oh-link
                  config:
                    action: options
                    actionItem: =loop.vanesItem.name
                    style:
                      margin-left: 20px
                  slots:
                    default:
                      - component: f7-chip
                        config:
                          text: "=items[loop.vanesItem.name].displayState ? items[loop.vanesItem.name].displayState : items[loop.vanesItem.name].state"
                      - component: oh-icon
                        config:
                          icon: f7:move
                          color: gray
                          width: 25px

To use it, add the following at the end of your room card:

    - component: oh-repeater
      config:
        fetchMetadata: semantics,metadata,listWidget
        for: hvacItem
        sourceType: itemsWithTags
        itemTags: HVAC
        filter: loop.hvacItem.metadata.semantics.config.hasLocation == vars.objVar.room
      slots:
        default:
          - component: oh-repeater
            config:
              fetchMetadata: semantics,metadata,listWidget
              for: hvacPowerItem
              sourceType: itemsWithTags
              itemTags: Control,Power
              filter: '((loop.hvacPowerItem.groupNames.indexOf(loop.hvacItem.name) >= 0) && (loop.hvacPowerItem.type=="Switch")) ? true : false'
            slots:
              default:
                - component: oh-repeater
                  config:
                    fetchMetadata: semantics,metadata,listWidget
                    for: hvacModeItem
                    sourceType: itemsWithTags
                    itemTags: Control,Temperature
                    filter: '((loop.hvacModeItem.groupNames.indexOf(loop.hvacItem.name) >= 0) && (loop.hvacModeItem.type=="String")) ? true : false'
                  slots:
                    default:
                      - component: widget:main_widget_HVAC_Card
                        config:
                          Title: =loop.hvacItem.label
                          groupItem: =loop.hvacItem.name
                          powerItem: =loop.hvacPowerItem.name
                          modeItem: =loop.hvacModeItem.name
                          visible: '=vars.objVar.selectThing=="Climate" ? true : false'

Checking your new radiator control card.
Don’t know why, but the card has different size than the three blocks used …

Ahh, have to look for it.

Did you try with iPhone or with browser?

EDIT: iPhone looks good for me, but desktop not - will have a look this evening…

Found it, it is the padding in line 16, change it back to 0px looks better.

Yes, the padding looks curious. What’s curious too is that the up and down arrows are not aligned right…

Indeed, I had to use margins in the HVAC card to achieve this, which I really don’t like.

If you find a better solution, feel free to post :wink: