Skip to content

Commit

Permalink
improvements to long-click accessory control
Browse files Browse the repository at this point in the history
  • Loading branch information
bwp91 committed Feb 8, 2025
1 parent ed1c43c commit 08bc59d
Show file tree
Hide file tree
Showing 61 changed files with 401 additions and 595 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ All notable changes to `homebridge-config-ui-x` will be documented in this file.
### UI Changes

- updates to the `th.json` language file (#2338) (@tomzt)
- improvements to long-click accessory control
- also fixes accessory and room rearranging on the accessories page
- accessory and status page layout will now be locked by default on each visit

### Other Changes

Expand Down
36 changes: 18 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
"unzipper": "0.12.3"
},
"devDependencies": {
"@antfu/eslint-config": "^4.1.0",
"@antfu/eslint-config": "^4.1.1",
"@nestjs/testing": "^10.4.15",
"@prettier/plugin-xml": "^3.4.1",
"@types/fs-extra": "^11.0.4",
Expand Down
2 changes: 0 additions & 2 deletions ui/src/app/core/accessories/accessories.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import { ThermostatComponent } from '@/app/core/accessories/types/thermostat/the
import { ThermostatManageComponent } from '@/app/core/accessories/types/thermostat/thermostat.manage.component'
import { UnknownComponent } from '@/app/core/accessories/types/unknown/unknown.component'
import { ValveComponent } from '@/app/core/accessories/types/valve/valve.component'
import { ValveManageComponent } from '@/app/core/accessories/types/valve/valve.manage.component'
import { WindowComponent } from '@/app/core/accessories/types/window/window.component'
import { WindowManageComponent } from '@/app/core/accessories/types/window/window.manage.component'
import { WindowCoveringComponent } from '@/app/core/accessories/types/windowcovering/windowcovering.component'
Expand Down Expand Up @@ -103,7 +102,6 @@ import { WindowcoveringManageComponent } from '@/app/core/accessories/types/wind
LeaksensorComponent,
SmokesensorComponent,
ValveComponent,
ValveManageComponent,
IrrigationSystemComponent,
AirpurifierComponent,
AirpurifierManageComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class AirpurifierComponent {

onLongClick() {
const ref = this.$modal.open(AirpurifierManageComponent, {
size: 'sm',
size: 'md',
})
ref.componentInstance.service = this.service
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,37 @@ <h5 class="modal-title" [innerText]="service.customName || service.serviceName">
(click)="$activeModal.dismiss('Dismiss')"
></button>
</div>
<div class="modal-body text-center">
<h5>
<strong>
{{ (service.values.Active ? 'accessories.control.on' : 'accessories.control.off') | translate }}
</strong>
</h5>

<div class="modal-body text-center px-5">
<h6>{{ 'menu.label_status' | translate }}</h6>
<div
class="btn-group-vertical d-flex justify-content-center mb-4 p-0"
class="btn-group-vertical d-flex justify-content-center mb-0 p-0"
role="group"
aria-label="Air Purifier Mode Control"
>
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setTargetMode(0)"
[ngClass]="{ 'btn-primary': targetMode === 0, 'btn-elegant': targetMode !== 0 }"
>
<button type="button" class="btn mb-0 mx-0 p-3 btn-control" (click)="setTargetMode(0); $event.target.blur()">
<div class="float-start primary-text">
<i
class="fas fa-fw fa-xl"
[ngClass]="{ 'fa-check-circle': targetMode === 0, 'fa-blank': targetMode !== 0 }"
></i>
</div>
{{ 'accessories.control.off' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setTargetMode(1)"
[ngClass]="{ 'btn-primary': targetMode === 1, 'btn-elegant': targetMode !== 1 }"
>
<button type="button" class="btn mb-0 mx-0 p-3 btn-control" (click)="setTargetMode(1); $event.target.blur()">
<div class="float-start primary-text">
<i
class="fas fa-fw fa-xl"
[ngClass]="{ 'fa-check-circle': targetMode === 1, 'fa-blank': targetMode !== 1 }"
></i>
</div>
{{ 'accessories.control.on' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
</div>

@if (targetRotationSpeed) {
<h5 class="mb-0">{{ 'accessories.control.rotation_speed' | translate }}</h5>
<p>{{ targetRotationSpeed.value }}%</p>
<h6 class="mt-4">{{ 'accessories.control.rotation_speed' | translate }}: {{ targetRotationSpeed.value }}%</h6>
<nouislider
[min]="targetRotationSpeed.min"
[max]="targetRotationSpeed.max"
Expand Down
24 changes: 10 additions & 14 deletions ui/src/app/core/accessories/types/door/door.manage.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,17 @@ <h5 class="modal-title" [innerText]="service.customName || service.serviceName">
></button>
</div>
<div class="modal-body text-center px-5">
<h5>
<strong>
@if (service.values.PositionState === 2) { @if (service.values.CurrentPosition === 0) { {{
'accessories.control.closed' | translate }} } @if (service.values.CurrentPosition > 0 &&
service.values.CurrentPosition < 100) { {{ service.values.CurrentPosition }}% {{ 'accessories.control.open' |
translate }} } @if (service.values.CurrentPosition === 100) { {{ 'accessories.control.open' | translate }} } }
@if (service.values.PositionState === 1) {
<div class="red-text">{{ 'accessories.control.opening' | translate }}...</div>
} @if (service.values.PositionState === 0) {
<div class="red-text">{{ 'accessories.control.closing' | translate }}...</div>
}
</strong>
</h5>
<h6 class="mb-4">
{{ 'menu.label_status' | translate }}: @if (service.values.PositionState === 2) { @if
(service.values.CurrentPosition === 0) { {{ 'accessories.control.closed' | translate }} } @if
(service.values.CurrentPosition > 0 && service.values.CurrentPosition < 100) { {{ 'accessories.control.open' |
translate }} <span class="grey-text"> ({{ service.values.CurrentPosition }}%)</span> } @if
(service.values.CurrentPosition === 100) { {{ 'accessories.control.open' | translate }} } } @if
(service.values.PositionState === 1) { {{ 'accessories.control.opening' | translate }}... } @if
(service.values.PositionState === 0) { {{ 'accessories.control.closing' | translate }}... }
</h6>

<p>{{ 'accessories.control.target' | translate }}: {{ targetPosition.value }}%</p>
<h6>{{ 'accessories.control.target' | translate }}: {{ targetPosition.value }}%</h6>
<nouislider
[min]="targetPosition.min"
[max]="targetPosition.max"
Expand Down
64 changes: 36 additions & 28 deletions ui/src/app/core/accessories/types/fan/fan.manage.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,29 @@ <h5 class="modal-title" [innerText]="service.customName || service.serviceName">
></button>
</div>
<div class="modal-body text-center px-5">
<h5>
{{ 'accessories.control.fan' | translate }} {{ (service.values.On ? 'accessories.control.on' :
'accessories.control.off') | translate }}
</h5>

<div class="btn-group-vertical d-flex justify-content-center mb-4 p-0" role="group" aria-label="Fan Mode Control">
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setTargetMode(false)"
[ngClass]="{ 'btn-primary': !targetMode, 'btn-elegant': targetMode }"
>
<h6>{{ 'menu.label_status' | translate }}</h6>
<div class="btn-group-vertical d-flex justify-content-center mb-0 p-0" role="group" aria-label="Fan Mode Control">
<button type="button" class="btn mb-0 mx-0 p-3 btn-control" (click)="setTargetMode(false); $event.target.blur()">
<div class="float-start primary-text">
<i class="fas fa-fw fa-xl" [ngClass]="{ 'fa-check-circle': !targetMode, 'fa-blank': targetMode }"></i>
</div>
{{ 'accessories.control.off' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setTargetMode(true)"
[ngClass]="{ 'btn-primary': targetMode, 'btn-elegant': !targetMode }"
>
<button type="button" class="btn mb-0 mx-0 p-3 btn-control" (click)="setTargetMode(true); $event.target.blur()">
<div class="float-start primary-text">
<i class="fas fa-fw fa-xl" [ngClass]="{ 'fa-check-circle': targetMode, 'fa-blank': !targetMode }"></i>
</div>
{{ 'accessories.control.on' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
</div>

@if (targetRotationSpeed) {
<h5 class="mb-0">{{ 'accessories.control.rotation_speed' | translate }}</h5>
<p>{{ targetRotationSpeed.value }}@if (targetRotationSpeed.unit === 'percentage') { % }</p>
<h6 class="mt-4">
{{ 'accessories.control.rotation_speed' | translate }}: {{ targetRotationSpeed.value }}@if
(targetRotationSpeed.unit === 'percentage') {%}
</h6>
<nouislider
[min]="targetRotationSpeed.min"
[max]="targetRotationSpeed.max"
Expand All @@ -45,28 +41,40 @@ <h5 class="mb-0">{{ 'accessories.control.rotation_speed' | translate }}</h5>
(ngModelChange)="onTargetRotationSpeedChange()"
>
</nouislider>
} @if (hasRotationDirection && targetMode) {
<h5 class="mt-4">{{ 'accessories.control.rotation_direction' | translate }}</h5>
} @if (hasRotationDirection) {
<h6 class="mt-4">{{ 'accessories.control.rotation_direction' | translate }}</h6>
<div
class="btn-group-vertical d-flex justify-content-center mb-4 p-0"
role="group"
aria-label="Fan Direction Control"
>
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setRotationDirection(0)"
[ngClass]="{ 'btn-primary': service.values.RotationDirection === 0, 'btn-elegant': service.values.RotationDirection !== 0 }"
class="btn mb-0 mx-0 p-3 btn-control"
(click)="setRotationDirection(0); $event.target.blur()"
>
<div class="float-start primary-text">
<i
class="fas fa-fw fa-xl"
[ngClass]="{ 'fa-check-circle': service.values.RotationDirection === 0, 'fa-blank': service.values.RotationDirection !== 0 }"
></i>
</div>
{{ 'accessories.control.rotation_clockwise' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setRotationDirection(1)"
[ngClass]="{ 'btn-primary': service.values.RotationDirection === 1, 'btn-elegant': service.values.RotationDirection !== 1 }"
class="btn mb-0 mx-0 p-3 btn-control"
(click)="setRotationDirection(1); $event.target.blur()"
>
<div class="float-start primary-text">
<i
class="fas fa-fw fa-xl"
[ngClass]="{ 'fa-check-circle': service.values.RotationDirection === 1, 'fa-blank': service.values.RotationDirection !== 1 }"
></i>
</div>
{{ 'accessories.control.rotation_c_clockwise' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
</div>
}
Expand Down
46 changes: 24 additions & 22 deletions ui/src/app/core/accessories/types/fanv2/fanv2.manage.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,35 @@ <h5 class="modal-title" [innerText]="service.customName || service.serviceName">
></button>
</div>
<div class="modal-body text-center px-5">
<h5>
{{ 'accessories.control.fan' | translate }} {{ (service.values.Active ? 'accessories.control.on' :
'accessories.control.off') | translate }}
</h5>

<div class="btn-group-vertical d-flex justify-content-center mb-4 p-0" role="group" aria-label="Fan Mode Control">
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setTargetMode(0)"
[ngClass]="{ 'btn-primary': targetMode === 0, 'btn-elegant': targetMode !== 0 }"
>
<h6>{{ 'menu.label_status' | translate }}</h6>
<div class="btn-group-vertical d-flex justify-content-center mb-0 p-0" role="group" aria-label="Fan Mode Control">
<button type="button" class="btn mb-0 mx-0 p-3 btn-control" (click)="setTargetMode(0); $event.target.blur()">
<div class="float-start primary-text">
<i
class="fas fa-fw fa-xl"
[ngClass]="{ 'fa-check-circle': targetMode === 0, 'fa-blank': targetMode !== 0 }"
></i>
</div>
{{ 'accessories.control.off' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
<button
type="button"
class="btn mb-0 mx-0 px-0 py-3"
(click)="setTargetMode(1)"
[ngClass]="{ 'btn-primary': targetMode === 1, 'btn-elegant': targetMode !== 1 }"
>
<button type="button" class="btn mb-0 mx-0 p-3 btn-control" (click)="setTargetMode(1); $event.target.blur()">
<div class="float-start primary-text">
<i
class="fas fa-fw fa-xl"
[ngClass]="{ 'fa-check-circle': targetMode === 1, 'fa-blank': targetMode !== 1 }"
></i>
</div>
{{ 'accessories.control.on' | translate }}
<div class="float-end"><i class="fas fa-fw fa-xl fa-blank"></i></div>
</button>
</div>

@if (targetRotationSpeed) {
<h5 class="mb-0">{{ 'accessories.control.rotation_speed' | translate }}</h5>
<p>{{ targetRotationSpeed.value }}@if (targetRotationSpeed.unit === 'percentage') { % }</p>
<h6 class="mt-4">
{{ 'accessories.control.rotation_speed' | translate }}: {{ targetRotationSpeed.value }}@if
(targetRotationSpeed.unit === 'percentage') {%}
</h6>
<nouislider
[min]="targetRotationSpeed.min"
[max]="targetRotationSpeed.max"
Expand All @@ -45,8 +47,8 @@ <h5 class="mb-0">{{ 'accessories.control.rotation_speed' | translate }}</h5>
(ngModelChange)="onTargetRotationSpeedChange()"
>
</nouislider>
} @if (hasRotationDirection && targetMode === 1) {
<h5 class="mt-4">{{ 'accessories.control.rotation_direction' | translate }}</h5>
} @if (hasRotationDirection) {
<h6 class="mt-4">{{ 'accessories.control.rotation_direction' | translate }}</h6>
<div
class="btn-group-vertical d-flex justify-content-center mb-4 p-0"
role="group"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class HeaterCoolerComponent {

onLongClick() {
const ref = this.$modal.open(HeaterCoolerManageComponent, {
size: 'sm',
size: 'md',
})
ref.componentInstance.service = this.service
}
Expand Down
Loading

0 comments on commit 08bc59d

Please sign in to comment.