forked from platypush/platypush
[light.hue] Support bridges with ungrouped lights.
This commit is contained in:
parent
f3aa245c0e
commit
14f979049b
4 changed files with 221 additions and 145 deletions
|
@ -3,7 +3,7 @@
|
||||||
<MenuPanel>
|
<MenuPanel>
|
||||||
<div class="panel-row header">
|
<div class="panel-row header">
|
||||||
<div class="col-3" v-if="group">
|
<div class="col-3" v-if="group">
|
||||||
<button class="back-btn" title="Back" @click="close">
|
<button class="back-btn" title="Back" @click="close" v-if="withBackButton">
|
||||||
<i class="fas fa-chevron-left" />
|
<i class="fas fa-chevron-left" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
v-text="groupName" @click="selectedView = selectedView === 'group' ? null : 'group'" />
|
v-text="groupName" @click="selectedView = selectedView === 'group' ? null : 'group'" />
|
||||||
|
|
||||||
<div class="col-3 pull-right" v-if="group">
|
<div class="col-3 pull-right" v-if="group">
|
||||||
<ToggleSwitch :value="group.state.any_on" @input="$emit('group-toggle', group)" />
|
<ToggleSwitch :value="anyLightsOn" @input="$emit('group-toggle', group)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
<div class="lights-view" v-else>
|
<div class="lights-view" v-else>
|
||||||
<div class="row view-selector">
|
<div class="row view-selector">
|
||||||
<button :class="{selected: selectedView === 'lights'}" title="Lights" @click="selectedView = 'lights'">
|
<button :class="{selected: selectedView === 'lights'}" :title="title" @click="selectedView = 'lights'">
|
||||||
<i class="icon fas fa-lightbulb" />
|
<i class="icon fas fa-lightbulb" />
|
||||||
</button>
|
</button>
|
||||||
<button :class="{selected: selectedView === 'scenes'}" title="Scenes" @click="selectedView = 'scenes'">
|
<button :class="{selected: selectedView === 'scenes'}" title="Scenes" @click="selectedView = 'scenes'">
|
||||||
|
@ -98,6 +98,11 @@ export default {
|
||||||
type: Object,
|
type: Object,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: 'Lights',
|
||||||
|
},
|
||||||
|
|
||||||
animations: {
|
animations: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
|
@ -107,6 +112,11 @@ export default {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => new ColorConverter(),
|
default: () => new ColorConverter(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
withBackButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@ -118,6 +128,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
anyLightsOn() {
|
||||||
|
if (this.group?.state?.any_on != null)
|
||||||
|
return this.group.state.any_on
|
||||||
|
|
||||||
|
return Object.values(this.lights).some(light => light.state.on)
|
||||||
|
},
|
||||||
|
|
||||||
lightsSorted() {
|
lightsSorted() {
|
||||||
if (!this.lights)
|
if (!this.lights)
|
||||||
return []
|
return []
|
||||||
|
@ -151,7 +168,7 @@ export default {
|
||||||
return this.group.name
|
return this.group.name
|
||||||
if (this.group?.id != null)
|
if (this.group?.id != null)
|
||||||
return `[Group ${this.group.id}]`
|
return `[Group ${this.group.id}]`
|
||||||
return 'Lights'
|
return this.title
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -169,90 +186,6 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.light-group-container {
|
@import "./groups.scss";
|
||||||
width: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
|
|
||||||
.row.panel-row {
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&.expanded,
|
|
||||||
&.selected {
|
|
||||||
background: $selected-bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 0.5em !important;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.back-btn {
|
|
||||||
border: 0;
|
|
||||||
background: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border: 0;
|
|
||||||
color: $default-hover-fg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
color: $selected-fg;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $default-hover-fg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-selector {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 0;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 33.3%;
|
|
||||||
padding: 1.5em;
|
|
||||||
text-align: left;
|
|
||||||
opacity: 0.8;
|
|
||||||
box-shadow: $plugin-panel-entry-shadow;
|
|
||||||
border-right: 0;
|
|
||||||
|
|
||||||
&.selected {
|
|
||||||
background: $selected-bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $hover-bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.light-group-container {
|
|
||||||
.group-controls {
|
|
||||||
margin: 0;
|
|
||||||
padding: 1em;
|
|
||||||
background-color: $default-bg-6;
|
|
||||||
border-radius: 0 0 1em 1em;
|
|
||||||
|
|
||||||
.controls {
|
|
||||||
margin: 0;
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<MenuPanel>
|
<div class="light-groups-container">
|
||||||
<div class="panel-row header">
|
<MenuPanel>
|
||||||
<div class="col-3">
|
<div class="panel-row header">
|
||||||
<i class="icon fas fa-home" />
|
<div class="col-3">
|
||||||
|
<i class="icon fas fa-home" />
|
||||||
|
</div>
|
||||||
|
<div class="col-6 name">
|
||||||
|
Rooms
|
||||||
|
</div>
|
||||||
|
<div class="col-3 pull-right">
|
||||||
|
<ToggleSwitch :value="anyLightsOn" @input="$emit('toggle')" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 name">
|
|
||||||
Rooms
|
|
||||||
</div>
|
|
||||||
<div class="col-3 pull-right">
|
|
||||||
<ToggleSwitch :value="anyLightsOn" @input="$emit('toggle')" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-row row group" v-for="group in groupsSorted" :key="group.id" @click="$emit('select', group.id)">
|
<div class="panel-row row group" v-for="group in groupsSorted" :key="group.id" @click="$emit('select', group.id)">
|
||||||
<span class="name col-9">
|
<span class="name col-9">
|
||||||
{{ group.name || `[Group ${group.id}]` }}
|
{{ group.name || `[Group ${group.id}]` }}
|
||||||
</span>
|
</span>
|
||||||
<span class="controls col-3 pull-right">
|
<span class="controls col-3 pull-right">
|
||||||
<ToggleSwitch :value="group.state.any_on" :disabled="group.id in (loadingGroups || {})"
|
<ToggleSwitch :value="group.state.any_on" :disabled="group.id in (loadingGroups || {})"
|
||||||
@input="$emit('toggle', group)" />
|
@input="$emit('toggle', group)" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</MenuPanel>
|
</MenuPanel>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -74,23 +76,5 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.header {
|
@import "./groups.scss";
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 0.75em !important;
|
|
||||||
padding-bottom: 0.75em !important;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-left: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.group {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
105
platypush/backend/http/webapp/src/components/Light/groups.scss
Normal file
105
platypush/backend/http/webapp/src/components/Light/groups.scss
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
.light-group-container {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
|
||||||
|
.row.panel-row {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&.expanded,
|
||||||
|
&.selected {
|
||||||
|
background: $selected-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 0.5em !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.back-btn {
|
||||||
|
border: 0;
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: 0;
|
||||||
|
color: $default-hover-fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
color: $selected-fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $default-hover-fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-selector {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 33.3%;
|
||||||
|
padding: 1.5em;
|
||||||
|
text-align: left;
|
||||||
|
opacity: 0.8;
|
||||||
|
box-shadow: $plugin-panel-entry-shadow;
|
||||||
|
border-right: 0;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background: $selected-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $hover-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.light-group-container) {
|
||||||
|
.group-controls {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1em;
|
||||||
|
background-color: $default-bg-6;
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.light-groups-container {
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 0.75em !important;
|
||||||
|
padding-bottom: 0.75em !important;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,46 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="plugin lights-plugin">
|
<div class="plugin lights-plugin">
|
||||||
<div class="panel" v-if="selectedGroup == null && groups && Object.keys(groups).length">
|
<div class="panel">
|
||||||
<Groups :groups="groups" :loading-groups="loadingGroups" :color-converter="colorConverter"
|
<div class="groups lights-container" v-if="selectedGroup == null && Object.keys(groups || {}).length">
|
||||||
@select="selectedGroup = $event" @toggle="$emit('group-toggle', $event)" />
|
<Groups :groups="groups"
|
||||||
</div>
|
:loading-groups="loadingGroups"
|
||||||
<div class="panel" v-else>
|
:color-converter="colorConverter"
|
||||||
<Group :group="groups[selectedGroup]" :lights="displayedLights" :scenes="scenesByGroup[selectedGroup]"
|
@select="selectedGroup = $event"
|
||||||
:color-converter="colorConverter" :animations="animationsByGroup[selectedGroup]" @close="selectedGroup = null"
|
@toggle="$emit('group-toggle', $event)" />
|
||||||
@light-toggle="$emit('light-toggle', $event)" @group-toggle="$emit('group-toggle', $event)"
|
</div>
|
||||||
@set-light="$emit('set-light', $event)"
|
|
||||||
@set-group="$emit('set-group', {groupId: selectedGroup, value: $event})"
|
<div class="lights-container ungrouped-lights"
|
||||||
@select-scene="$emit('select-scene', {groupId: selectedGroup, sceneId: $event})"
|
v-if="Object.keys(ungroupedLights || {}).length && selectedGroup == null">
|
||||||
@start-animation="$emit('start-animation', $event)" @stop-animation="$emit('stop-animation', $event)" />
|
<Group :group="ungroupedLights"
|
||||||
|
:lights="ungroupedLights"
|
||||||
|
:scenes="scenesByGroup[selectedGroup]"
|
||||||
|
:color-converter="colorConverter"
|
||||||
|
:animations="animationsByGroup[selectedGroup]"
|
||||||
|
:with-back-button="false"
|
||||||
|
title="Ungrouped Lights"
|
||||||
|
@close="selectedGroup = null"
|
||||||
|
@light-toggle="$emit('light-toggle', $event)"
|
||||||
|
@select-scene="$emit('select-scene', {groupId: selectedGroup, sceneId: $event})"
|
||||||
|
@set-light="$emit('set-light', $event)"
|
||||||
|
@start-animation="$emit('start-animation', $event)"
|
||||||
|
@stop-animation="$emit('stop-animation', $event)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="group" v-if="groups?.[selectedGroup]">
|
||||||
|
<Group :group="groups[selectedGroup]"
|
||||||
|
:lights="displayedLights"
|
||||||
|
:scenes="scenesByGroup[selectedGroup]"
|
||||||
|
:color-converter="colorConverter"
|
||||||
|
:animations="animationsByGroup[selectedGroup]"
|
||||||
|
@close="selectedGroup = null"
|
||||||
|
@group-toggle="$emit('group-toggle', $event)"
|
||||||
|
@light-toggle="$emit('light-toggle', $event)"
|
||||||
|
@select-scene="$emit('select-scene', {groupId: selectedGroup, sceneId: $event})"
|
||||||
|
@set-group="$emit('set-group', {groupId: selectedGroup, value: $event})"
|
||||||
|
@set-light="$emit('set-light', $event)"
|
||||||
|
@start-animation="$emit('start-animation', $event)"
|
||||||
|
@stop-animation="$emit('stop-animation', $event)" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -27,9 +56,12 @@ import {ColorConverter} from "@/components/panels/Light/color";
|
||||||
* Generic component for light plugins panels.
|
* Generic component for light plugins panels.
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
name: "Light",
|
|
||||||
components: {Group, Groups},
|
|
||||||
mixins: [Utils, Panel],
|
mixins: [Utils, Panel],
|
||||||
|
components: {
|
||||||
|
Group,
|
||||||
|
Groups,
|
||||||
|
},
|
||||||
|
|
||||||
emits: [
|
emits: [
|
||||||
'group-toggle',
|
'group-toggle',
|
||||||
'light-changed',
|
'light-changed',
|
||||||
|
@ -113,6 +145,15 @@ export default {
|
||||||
}, {})
|
}, {})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ungroupedLights() {
|
||||||
|
return Object.keys(this.lights || {})
|
||||||
|
.filter((lightId) => !this.groupsByLight[lightId])
|
||||||
|
.reduce((obj, lightId) => {
|
||||||
|
obj[lightId] = this.lights[lightId]
|
||||||
|
return obj
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
|
||||||
scenesByGroup() {
|
scenesByGroup() {
|
||||||
if (!this.scenes)
|
if (!this.scenes)
|
||||||
return {}
|
return {}
|
||||||
|
@ -120,10 +161,16 @@ export default {
|
||||||
const self = this
|
const self = this
|
||||||
return Object.entries(this.scenes).reduce((obj, [sceneId, scene]) => {
|
return Object.entries(this.scenes).reduce((obj, [sceneId, scene]) => {
|
||||||
scene.lights.forEach((lightId) => {
|
scene.lights.forEach((lightId) => {
|
||||||
|
if (!self.groupsByLight[lightId]) {
|
||||||
|
if (!obj[-1])
|
||||||
|
obj[-1] = {}
|
||||||
|
obj[-1][sceneId] = scene
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Object.keys(self.groupsByLight[lightId]).forEach((groupId) => {
|
Object.keys(self.groupsByLight[lightId]).forEach((groupId) => {
|
||||||
if (!obj[groupId])
|
if (!obj[groupId])
|
||||||
obj[groupId] = {}
|
obj[groupId] = {}
|
||||||
|
|
||||||
obj[groupId][sceneId] = scene
|
obj[groupId][sceneId] = scene
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -152,6 +199,10 @@ export default {
|
||||||
obj[group.id] = {}
|
obj[group.id] = {}
|
||||||
obj[group.id][lightId] = animation
|
obj[group.id][lightId] = animation
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (!obj[-1])
|
||||||
|
obj[-1] = {}
|
||||||
|
obj[-1][lightId] = animation
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
@ -229,6 +280,7 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
|
@ -240,6 +292,8 @@ export default {
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import "@/components/Light/groups.scss";
|
||||||
|
|
||||||
.lights-plugin {
|
.lights-plugin {
|
||||||
.menu-panel {
|
.menu-panel {
|
||||||
ul {
|
ul {
|
||||||
|
|
Loading…
Reference in a new issue