@camstack/ui-library 1.2.375 → 1.2.377
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/{MotionZonesSettings-Zcfa5c9l.js → MotionZonesSettings-BvpjmW6y.js} +1 -1
- package/dist/{PrivacyMaskSettings-B_X42yzN.js → PrivacyMaskSettings-D7o4tx8e.js} +1 -1
- package/dist/{SceneMonitorEditor-C8YXVzYI.js → SceneMonitorEditor-BwelmHlF.js} +1 -1
- package/dist/composites/cap-settings/PowerMeterLine.d.ts +10 -0
- package/dist/composites/cap-settings/index.d.ts +1 -0
- package/dist/composites/device-controls/appliance-control.d.ts +0 -2
- package/dist/composites/device-controls/media-player-hero-card.d.ts +15 -10
- package/dist/composites/device-controls/media-player-hero-parts.d.ts +18 -0
- package/dist/composites/device-controls/media-player-panel.d.ts +1 -1
- package/dist/composites/device-controls/media-player-view.d.ts +66 -0
- package/dist/composites/index.d.ts +1 -0
- package/dist/generated/system-hooks.d.ts +14 -0
- package/dist/{icons-DXwPEKdJ.cjs → icons-BWpVdTJu.cjs} +3 -83
- package/dist/{icons-e-xohmFb.js → icons-cIFSolkx.js} +1 -81
- package/dist/index.cjs +781 -156
- package/dist/index.js +776 -162
- package/dist/primitives/bottom-sheet.d.ts +1 -1
- package/dist/primitives/mobile-drawer.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3471,6 +3471,58 @@ var RefreshCw = require_createLucideIcon.createLucideIcon("refresh-cw", [
|
|
|
3471
3471
|
* This source code is licensed under the ISC license.
|
|
3472
3472
|
* See the LICENSE file in the root directory of this source tree.
|
|
3473
3473
|
*/
|
|
3474
|
+
var Repeat1 = require_createLucideIcon.createLucideIcon("repeat-1", [
|
|
3475
|
+
["path", {
|
|
3476
|
+
d: "m17 2 4 4-4 4",
|
|
3477
|
+
key: "nntrym"
|
|
3478
|
+
}],
|
|
3479
|
+
["path", {
|
|
3480
|
+
d: "M3 11v-1a4 4 0 0 1 4-4h14",
|
|
3481
|
+
key: "84bu3i"
|
|
3482
|
+
}],
|
|
3483
|
+
["path", {
|
|
3484
|
+
d: "m7 22-4-4 4-4",
|
|
3485
|
+
key: "1wqhfi"
|
|
3486
|
+
}],
|
|
3487
|
+
["path", {
|
|
3488
|
+
d: "M21 13v1a4 4 0 0 1-4 4H3",
|
|
3489
|
+
key: "1rx37r"
|
|
3490
|
+
}],
|
|
3491
|
+
["path", {
|
|
3492
|
+
d: "M11 10h1v4",
|
|
3493
|
+
key: "70cz1p"
|
|
3494
|
+
}]
|
|
3495
|
+
]);
|
|
3496
|
+
/**
|
|
3497
|
+
* @license lucide-react v0.576.0 - ISC
|
|
3498
|
+
*
|
|
3499
|
+
* This source code is licensed under the ISC license.
|
|
3500
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
3501
|
+
*/
|
|
3502
|
+
var Repeat = require_createLucideIcon.createLucideIcon("repeat", [
|
|
3503
|
+
["path", {
|
|
3504
|
+
d: "m17 2 4 4-4 4",
|
|
3505
|
+
key: "nntrym"
|
|
3506
|
+
}],
|
|
3507
|
+
["path", {
|
|
3508
|
+
d: "M3 11v-1a4 4 0 0 1 4-4h14",
|
|
3509
|
+
key: "84bu3i"
|
|
3510
|
+
}],
|
|
3511
|
+
["path", {
|
|
3512
|
+
d: "m7 22-4-4 4-4",
|
|
3513
|
+
key: "1wqhfi"
|
|
3514
|
+
}],
|
|
3515
|
+
["path", {
|
|
3516
|
+
d: "M21 13v1a4 4 0 0 1-4 4H3",
|
|
3517
|
+
key: "1rx37r"
|
|
3518
|
+
}]
|
|
3519
|
+
]);
|
|
3520
|
+
/**
|
|
3521
|
+
* @license lucide-react v0.576.0 - ISC
|
|
3522
|
+
*
|
|
3523
|
+
* This source code is licensed under the ISC license.
|
|
3524
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
3525
|
+
*/
|
|
3474
3526
|
var RotateCcw = require_createLucideIcon.createLucideIcon("rotate-ccw", [["path", {
|
|
3475
3527
|
d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
|
|
3476
3528
|
key: "1357e3"
|
|
@@ -3846,6 +3898,34 @@ var Ship = require_createLucideIcon.createLucideIcon("ship", [
|
|
|
3846
3898
|
* This source code is licensed under the ISC license.
|
|
3847
3899
|
* See the LICENSE file in the root directory of this source tree.
|
|
3848
3900
|
*/
|
|
3901
|
+
var Shuffle = require_createLucideIcon.createLucideIcon("shuffle", [
|
|
3902
|
+
["path", {
|
|
3903
|
+
d: "m18 14 4 4-4 4",
|
|
3904
|
+
key: "10pe0f"
|
|
3905
|
+
}],
|
|
3906
|
+
["path", {
|
|
3907
|
+
d: "m18 2 4 4-4 4",
|
|
3908
|
+
key: "pucp1d"
|
|
3909
|
+
}],
|
|
3910
|
+
["path", {
|
|
3911
|
+
d: "M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22",
|
|
3912
|
+
key: "1ailkh"
|
|
3913
|
+
}],
|
|
3914
|
+
["path", {
|
|
3915
|
+
d: "M2 6h1.972a4 4 0 0 1 3.6 2.2",
|
|
3916
|
+
key: "km57vx"
|
|
3917
|
+
}],
|
|
3918
|
+
["path", {
|
|
3919
|
+
d: "M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45",
|
|
3920
|
+
key: "os18l9"
|
|
3921
|
+
}]
|
|
3922
|
+
]);
|
|
3923
|
+
/**
|
|
3924
|
+
* @license lucide-react v0.576.0 - ISC
|
|
3925
|
+
*
|
|
3926
|
+
* This source code is licensed under the ISC license.
|
|
3927
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
3928
|
+
*/
|
|
3849
3929
|
var Siren = require_createLucideIcon.createLucideIcon("siren", [
|
|
3850
3930
|
["path", {
|
|
3851
3931
|
d: "M7 18v-6a5 5 0 1 1 10 0v6",
|
|
@@ -5994,7 +6074,7 @@ function lucideExportName(key) {
|
|
|
5994
6074
|
function loadIconGlyphs() {
|
|
5995
6075
|
if (fullTable !== void 0) return Promise.resolve();
|
|
5996
6076
|
if (failure$1 !== void 0) return Promise.reject(failure$1);
|
|
5997
|
-
pending ??= Promise.resolve().then(() => require("./icons-
|
|
6077
|
+
pending ??= Promise.resolve().then(() => require("./icons-BWpVdTJu.cjs")).then((module) => {
|
|
5998
6078
|
fullTable = module;
|
|
5999
6079
|
publish();
|
|
6000
6080
|
}, (error) => {
|
|
@@ -9739,14 +9819,15 @@ function BottomSheet({ open, onClose, title, children, className }) {
|
|
|
9739
9819
|
document.body.style.overflow = "";
|
|
9740
9820
|
};
|
|
9741
9821
|
}, [open, onClose]);
|
|
9822
|
+
if (!open) return null;
|
|
9742
9823
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9743
|
-
className:
|
|
9824
|
+
className: "fixed inset-0 z-40 bg-black/50 animate-in fade-in duration-200",
|
|
9744
9825
|
onClick: onClose,
|
|
9745
9826
|
"aria-hidden": "true"
|
|
9746
9827
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9747
9828
|
role: "dialog",
|
|
9748
9829
|
"aria-modal": "true",
|
|
9749
|
-
className: cn("fixed inset-x-0 bottom-0 z-50 flex flex-col bg-background-elevated border-t border-border rounded-t-xl shadow-2xl
|
|
9830
|
+
className: cn("fixed inset-x-0 bottom-0 z-50 flex flex-col bg-background-elevated border-t border-border rounded-t-xl shadow-2xl animate-in slide-in-from-bottom duration-200 ease-out pb-[env(safe-area-inset-bottom)]", "max-h-[80dvh]", className),
|
|
9750
9831
|
children: [
|
|
9751
9832
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9752
9833
|
className: "flex justify-center pt-2 pb-1",
|
|
@@ -11852,6 +11933,18 @@ var useLockControlUnlock = /*#__PURE__*/ alias(() => trpc.lockControl.unlock.use
|
|
|
11852
11933
|
var useLockControlOpen = /*#__PURE__*/ alias(() => trpc.lockControl.open.useMutation);
|
|
11853
11934
|
/** Generated alias around `trpc.lockControl.getStatus.useQuery`. */
|
|
11854
11935
|
var useLockControlGetStatus = /*#__PURE__*/ alias(() => trpc.lockControl.getStatus.useQuery);
|
|
11936
|
+
/** Generated alias around `trpc.mediaPlayer.turnOn.useMutation`. */
|
|
11937
|
+
var useMediaPlayerTurnOn = /*#__PURE__*/ alias(() => trpc.mediaPlayer.turnOn.useMutation);
|
|
11938
|
+
/** Generated alias around `trpc.mediaPlayer.turnOff.useMutation`. */
|
|
11939
|
+
var useMediaPlayerTurnOff = /*#__PURE__*/ alias(() => trpc.mediaPlayer.turnOff.useMutation);
|
|
11940
|
+
/** Generated alias around `trpc.mediaPlayer.volumeUp.useMutation`. */
|
|
11941
|
+
var useMediaPlayerVolumeUp = /*#__PURE__*/ alias(() => trpc.mediaPlayer.volumeUp.useMutation);
|
|
11942
|
+
/** Generated alias around `trpc.mediaPlayer.volumeDown.useMutation`. */
|
|
11943
|
+
var useMediaPlayerVolumeDown = /*#__PURE__*/ alias(() => trpc.mediaPlayer.volumeDown.useMutation);
|
|
11944
|
+
/** Generated alias around `trpc.mediaPlayer.channelUp.useMutation`. */
|
|
11945
|
+
var useMediaPlayerChannelUp = /*#__PURE__*/ alias(() => trpc.mediaPlayer.channelUp.useMutation);
|
|
11946
|
+
/** Generated alias around `trpc.mediaPlayer.channelDown.useMutation`. */
|
|
11947
|
+
var useMediaPlayerChannelDown = /*#__PURE__*/ alias(() => trpc.mediaPlayer.channelDown.useMutation);
|
|
11855
11948
|
/** Generated alias around `trpc.mediaPlayer.play.useMutation`. */
|
|
11856
11949
|
var useMediaPlayerPlay = /*#__PURE__*/ alias(() => trpc.mediaPlayer.play.useMutation);
|
|
11857
11950
|
/** Generated alias around `trpc.mediaPlayer.pause.useMutation`. */
|
|
@@ -12826,6 +12919,8 @@ var useRemoteSetConfig = /*#__PURE__*/ alias(() => trpc.remote.setConfig.useMuta
|
|
|
12826
12919
|
var useRemoteListCommands = /*#__PURE__*/ alias(() => trpc.remote.listCommands.useQuery);
|
|
12827
12920
|
/** Generated alias around `trpc.remote.sendCommand.useMutation`. */
|
|
12828
12921
|
var useRemoteSendCommand = /*#__PURE__*/ alias(() => trpc.remote.sendCommand.useMutation);
|
|
12922
|
+
/** Generated alias around `trpc.remote.getAssumedStatus.useQuery`. */
|
|
12923
|
+
var useRemoteGetAssumedStatus = /*#__PURE__*/ alias(() => trpc.remote.getAssumedStatus.useQuery);
|
|
12829
12924
|
/** Generated alias around `trpc.remote.sendMediaCommand.useMutation`. */
|
|
12830
12925
|
var useRemoteSendMediaCommand = /*#__PURE__*/ alias(() => trpc.remote.sendMediaCommand.useMutation);
|
|
12831
12926
|
/** Generated alias around `trpc.remoteLayoutComponents.listComponents.useQuery`. */
|
|
@@ -27746,6 +27841,92 @@ function NavigationPanel({ deviceId }) {
|
|
|
27746
27841
|
});
|
|
27747
27842
|
}
|
|
27748
27843
|
//#endregion
|
|
27844
|
+
//#region src/composites/cap-settings/PowerMeterLine.tsx
|
|
27845
|
+
/**
|
|
27846
|
+
* PowerMeterLine — the ONE place a device's electrical draw is shown (D1004):
|
|
27847
|
+
* a slim line directly under the device page's hero card, for every device
|
|
27848
|
+
* bound to the `power-meter` capability, whatever its type. The cap declares
|
|
27849
|
+
* `ui: { kind:'widget', widgetId:'host/power-meter-line', placement:'hero' }`;
|
|
27850
|
+
* no device-controls hero card draws watts itself
|
|
27851
|
+
* (`scripts/check-no-hero-self-drawn-power.ts`).
|
|
27852
|
+
*
|
|
27853
|
+
* A reading the device never reported is not drawn as a number: no slice, or
|
|
27854
|
+
* a slice with neither power nor energy, renders nothing; a missing field
|
|
27855
|
+
* (power but no energy, or the reverse) is simply absent, never `0` or `NaN`.
|
|
27856
|
+
*/
|
|
27857
|
+
/** A finite number, or null: the one gate between a slice field and the screen. */
|
|
27858
|
+
function known(value) {
|
|
27859
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
27860
|
+
}
|
|
27861
|
+
/** Whole watts below a kilowatt, one decimal above. */
|
|
27862
|
+
function formatPowerWatts(watts) {
|
|
27863
|
+
return Math.abs(watts) >= 1e3 ? {
|
|
27864
|
+
value: (watts / 1e3).toFixed(1),
|
|
27865
|
+
unit: "kW"
|
|
27866
|
+
} : {
|
|
27867
|
+
value: String(Math.round(watts)),
|
|
27868
|
+
unit: "W"
|
|
27869
|
+
};
|
|
27870
|
+
}
|
|
27871
|
+
/** Two decimals under 100 kWh, whole kWh above. */
|
|
27872
|
+
function formatEnergyKwh(kwh) {
|
|
27873
|
+
return Math.abs(kwh) >= 100 ? String(Math.round(kwh)) : kwh.toFixed(2);
|
|
27874
|
+
}
|
|
27875
|
+
function PowerMeterLine({ deviceId }) {
|
|
27876
|
+
const t = useUiText();
|
|
27877
|
+
const { slice } = useDeviceCapability({
|
|
27878
|
+
trpc: useSystem().trpcClient,
|
|
27879
|
+
deviceId,
|
|
27880
|
+
cap: (d) => d.powerMeter,
|
|
27881
|
+
slice: (d) => d.state.powerMeter
|
|
27882
|
+
});
|
|
27883
|
+
const power = known(slice?.power);
|
|
27884
|
+
const energy = known(slice?.energy);
|
|
27885
|
+
if (power === null && energy === null) return null;
|
|
27886
|
+
const drawing = power !== null && power > 0;
|
|
27887
|
+
const shown = power === null ? null : formatPowerWatts(power);
|
|
27888
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
27889
|
+
"data-testid": "power-meter-line",
|
|
27890
|
+
className: "flex items-center gap-3 rounded-lg border border-border bg-surface px-3 py-2",
|
|
27891
|
+
children: [
|
|
27892
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
27893
|
+
className: "relative flex h-5 w-5 shrink-0 items-center justify-center",
|
|
27894
|
+
children: [drawing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27895
|
+
"aria-hidden": "true",
|
|
27896
|
+
"data-testid": "power-meter-pulse",
|
|
27897
|
+
className: "absolute inset-0 rounded-full bg-primary/20 motion-safe:animate-pulse"
|
|
27898
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Zap, {
|
|
27899
|
+
className: cn("relative h-3.5 w-3.5", drawing ? "text-primary" : "text-foreground-subtle"),
|
|
27900
|
+
"aria-hidden": true
|
|
27901
|
+
})]
|
|
27902
|
+
}),
|
|
27903
|
+
shown !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
27904
|
+
"data-testid": "power-meter-power",
|
|
27905
|
+
className: "flex items-baseline gap-1 tabular-nums",
|
|
27906
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27907
|
+
className: "text-lg font-semibold text-foreground",
|
|
27908
|
+
children: shown.value
|
|
27909
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27910
|
+
className: "text-xs text-foreground-muted",
|
|
27911
|
+
children: shown.unit
|
|
27912
|
+
})]
|
|
27913
|
+
}),
|
|
27914
|
+
energy !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
27915
|
+
"data-testid": "power-meter-energy",
|
|
27916
|
+
className: "ml-auto flex items-baseline gap-1 tabular-nums",
|
|
27917
|
+
title: t("uiLibrary.powerMeterLine.energy", "Energy"),
|
|
27918
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27919
|
+
className: "text-sm text-foreground-muted",
|
|
27920
|
+
children: formatEnergyKwh(energy)
|
|
27921
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27922
|
+
className: "text-xs text-foreground-subtle",
|
|
27923
|
+
children: "kWh"
|
|
27924
|
+
})]
|
|
27925
|
+
})
|
|
27926
|
+
]
|
|
27927
|
+
});
|
|
27928
|
+
}
|
|
27929
|
+
//#endregion
|
|
27749
27930
|
//#region src/lib/cap-error.ts
|
|
27750
27931
|
/**
|
|
27751
27932
|
* Shared capability-error utilities for the admin UI.
|
|
@@ -30724,6 +30905,7 @@ var HOST_WIDGETS = {
|
|
|
30724
30905
|
"host/ptz-panel": PtzPanel,
|
|
30725
30906
|
"host/navigation-panel": NavigationPanel,
|
|
30726
30907
|
"host/consumables-panel": ConsumablesPanel,
|
|
30908
|
+
"host/power-meter-line": PowerMeterLine,
|
|
30727
30909
|
"host/ptz-autotrack": AutotrackSection,
|
|
30728
30910
|
"host/recording-panel": RecordingPanel,
|
|
30729
30911
|
"host/camera-grid-layout": CameraGridLayoutEditor,
|
|
@@ -36444,7 +36626,8 @@ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
|
|
|
36444
36626
|
document.body.style.overflow = "";
|
|
36445
36627
|
};
|
|
36446
36628
|
}, [open, onClose]);
|
|
36447
|
-
|
|
36629
|
+
if (!open) return null;
|
|
36630
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
36448
36631
|
className: "fixed inset-0 z-40 bg-black/50 animate-in fade-in duration-200",
|
|
36449
36632
|
onClick: onClose,
|
|
36450
36633
|
"aria-hidden": "true"
|
|
@@ -36452,7 +36635,7 @@ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
|
|
|
36452
36635
|
ref: drawerRef,
|
|
36453
36636
|
role: "dialog",
|
|
36454
36637
|
"aria-modal": "true",
|
|
36455
|
-
className: cn("fixed inset-y-0 left-0 z-50 flex flex-col bg-surface border-r border-border shadow-2xl
|
|
36638
|
+
className: cn("fixed inset-y-0 left-0 z-50 flex flex-col bg-surface border-r border-border shadow-2xl animate-in slide-in-from-left duration-200 ease-out pt-[env(safe-area-inset-top)] pb-[env(safe-area-inset-bottom)]", width, className),
|
|
36456
36639
|
children
|
|
36457
36640
|
})] });
|
|
36458
36641
|
}
|
|
@@ -36537,7 +36720,7 @@ function AppShell({ sidebar, header, mobileLogo, mobileActions, children, classN
|
|
|
36537
36720
|
className: "flex flex-1 flex-col min-w-0",
|
|
36538
36721
|
children: [
|
|
36539
36722
|
isMobile && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
36540
|
-
className: "flex items-center h-12 border-b border-border px-3 shrink-0 bg-surface
|
|
36723
|
+
className: "flex items-center h-12 border-b border-border px-3 shrink-0 bg-surface",
|
|
36541
36724
|
children: [
|
|
36542
36725
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
36543
36726
|
onClick: () => setDrawerOpen(true),
|
|
@@ -37059,8 +37242,8 @@ function pickWifiIcon(signalPercent) {
|
|
|
37059
37242
|
}
|
|
37060
37243
|
function signalColor(signalPercent) {
|
|
37061
37244
|
if (signalPercent === null) return "text-foreground-subtle";
|
|
37062
|
-
if (signalPercent <= 20) return "text-
|
|
37063
|
-
if (signalPercent <= 50) return "text-
|
|
37245
|
+
if (signalPercent <= 20) return "text-danger";
|
|
37246
|
+
if (signalPercent <= 50) return "text-warning";
|
|
37064
37247
|
return "text-foreground-subtle";
|
|
37065
37248
|
}
|
|
37066
37249
|
function NetworkLinkBadge({ status, className }) {
|
|
@@ -37071,15 +37254,16 @@ function NetworkLinkBadge({ status, className }) {
|
|
|
37071
37254
|
title: t("uiLibrary.networkLinkBadge.ethernet", "Network: ethernet"),
|
|
37072
37255
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Cable, { className: "h-3.5 w-3.5" })
|
|
37073
37256
|
});
|
|
37074
|
-
const
|
|
37075
|
-
const
|
|
37257
|
+
const reading = typeof status.signal === "number" && Number.isFinite(status.signal) ? status.signal : null;
|
|
37258
|
+
const Icon = status.type === "cellular" ? RadioTower : pickWifiIcon(reading);
|
|
37259
|
+
const signal = reading === null ? null : Math.round(reading);
|
|
37076
37260
|
const networkText = status.ssid ? t("uiLibrary.networkLinkBadge.typeSsid", "Network: {{type}} ({{ssid}})", {
|
|
37077
37261
|
type: status.type,
|
|
37078
37262
|
ssid: status.ssid
|
|
37079
37263
|
}) : t("uiLibrary.networkLinkBadge.type", "Network: {{type}}", { type: status.type });
|
|
37080
37264
|
const title = signal === null ? networkText : `${networkText} · ${t("uiLibrary.networkLinkBadge.signal", "signal {{percent}}%", { percent: signal })}`;
|
|
37081
37265
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
37082
|
-
className: cn("inline-flex items-center gap-1 text-[10px] font-medium", signalColor(
|
|
37266
|
+
className: cn("inline-flex items-center gap-1 text-[10px] font-medium", signalColor(reading), className),
|
|
37083
37267
|
title,
|
|
37084
37268
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { className: "h-3.5 w-3.5" }), signal !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [signal, "%"] })]
|
|
37085
37269
|
});
|
|
@@ -48766,29 +48950,179 @@ function ClimatePanel({ trpc, deviceId, features: _features, layout, optimistic
|
|
|
48766
48950
|
});
|
|
48767
48951
|
}
|
|
48768
48952
|
//#endregion
|
|
48953
|
+
//#region src/composites/device-controls/media-player-view.ts
|
|
48954
|
+
/**
|
|
48955
|
+
* The state → view mapping of the media-player hero card, kept pure so it can
|
|
48956
|
+
* be specified without rendering.
|
|
48957
|
+
*
|
|
48958
|
+
* Two questions are answered separately. POWER is whether the device is on
|
|
48959
|
+
* (`off` / `standby` / on); RUNNING is what a powered device is doing
|
|
48960
|
+
* (`playing` / `paused` / `buffering` / `idle`). A status that never arrived
|
|
48961
|
+
* is `unknown` for both, and an unknown state is never drawn as off: it is
|
|
48962
|
+
* its own look. A value the driver only guesses (infrared has no feedback)
|
|
48963
|
+
* carries an `assumed` flag so the card can draw it as a guess.
|
|
48964
|
+
*
|
|
48965
|
+
* The controls are derived from what the device exposes — the status fields
|
|
48966
|
+
* it fills and the `DeviceFeature` flags it declares — never from a vendor.
|
|
48967
|
+
*/
|
|
48968
|
+
var NO_TRANSPORT = {
|
|
48969
|
+
playPause: false,
|
|
48970
|
+
previous: false,
|
|
48971
|
+
next: false,
|
|
48972
|
+
stop: false
|
|
48973
|
+
};
|
|
48974
|
+
/** Whether the status carries any activity the device actually reported. */
|
|
48975
|
+
function runningOf(state) {
|
|
48976
|
+
switch (state) {
|
|
48977
|
+
case "playing":
|
|
48978
|
+
case "paused":
|
|
48979
|
+
case "buffering":
|
|
48980
|
+
case "idle": return state;
|
|
48981
|
+
case void 0: return "unknown";
|
|
48982
|
+
default: return "none";
|
|
48983
|
+
}
|
|
48984
|
+
}
|
|
48985
|
+
function artworkOf(status) {
|
|
48986
|
+
const url = status.currentMedia?.imageUrl?.trim() ?? "";
|
|
48987
|
+
return url === "" ? null : url;
|
|
48988
|
+
}
|
|
48989
|
+
function powerOf(state) {
|
|
48990
|
+
if (state === void 0) return "unknown";
|
|
48991
|
+
if (state === "off") return "off";
|
|
48992
|
+
if (state === "standby") return "standby";
|
|
48993
|
+
return "on";
|
|
48994
|
+
}
|
|
48995
|
+
/**
|
|
48996
|
+
* A slice from before `assumedFields` existed (stateSource assumed, no list)
|
|
48997
|
+
* means the whole state is a guess; with a list, only the named fields are.
|
|
48998
|
+
*/
|
|
48999
|
+
function isAssumed(status, field) {
|
|
49000
|
+
if (status.stateSource !== "assumed") return false;
|
|
49001
|
+
const listed = status.assumedFields ?? [];
|
|
49002
|
+
return listed.length === 0 || listed.includes(field);
|
|
49003
|
+
}
|
|
49004
|
+
var UNKNOWN_VIEW = {
|
|
49005
|
+
power: "unknown",
|
|
49006
|
+
runningReading: "unknown",
|
|
49007
|
+
running: "unknown",
|
|
49008
|
+
stateAssumed: false,
|
|
49009
|
+
canSwitchPower: false,
|
|
49010
|
+
transport: NO_TRANSPORT,
|
|
49011
|
+
seek: false,
|
|
49012
|
+
volume: "none",
|
|
49013
|
+
volumeAssumed: false,
|
|
49014
|
+
volumeKnown: false,
|
|
49015
|
+
muteKnown: false,
|
|
49016
|
+
artworkUrl: null,
|
|
49017
|
+
mute: false,
|
|
49018
|
+
muteAssumed: false,
|
|
49019
|
+
source: null,
|
|
49020
|
+
sourceAssumed: false,
|
|
49021
|
+
shuffle: false,
|
|
49022
|
+
repeat: false
|
|
49023
|
+
};
|
|
49024
|
+
function readingOf(running) {
|
|
49025
|
+
if (running === true) return "running";
|
|
49026
|
+
if (running === false) return "idle";
|
|
49027
|
+
return "unknown";
|
|
49028
|
+
}
|
|
49029
|
+
function deriveMediaPlayerView(status, features, extras = {}) {
|
|
49030
|
+
const runningReading = readingOf(extras.running);
|
|
49031
|
+
const view = deriveFromStatus(status, features);
|
|
49032
|
+
const guessed = status === void 0 || status.state === void 0 || view.stateAssumed;
|
|
49033
|
+
if (runningReading === "unknown" || !guessed) return {
|
|
49034
|
+
...view,
|
|
49035
|
+
runningReading
|
|
49036
|
+
};
|
|
49037
|
+
if (runningReading === "idle") return {
|
|
49038
|
+
...UNKNOWN_VIEW,
|
|
49039
|
+
power: "off",
|
|
49040
|
+
running: "none",
|
|
49041
|
+
canSwitchPower: view.canSwitchPower,
|
|
49042
|
+
runningReading
|
|
49043
|
+
};
|
|
49044
|
+
return {
|
|
49045
|
+
...status === void 0 ? view : deriveFromStatus(status.state === void 0 || status.state === "off" || status.state === "standby" ? {
|
|
49046
|
+
...status,
|
|
49047
|
+
state: "on"
|
|
49048
|
+
} : status, features),
|
|
49049
|
+
power: "on",
|
|
49050
|
+
stateAssumed: false,
|
|
49051
|
+
runningReading
|
|
49052
|
+
};
|
|
49053
|
+
}
|
|
49054
|
+
function deriveFromStatus(status, features) {
|
|
49055
|
+
const has = (f) => features?.includes(f) ?? false;
|
|
49056
|
+
const canSwitchPower = has(_camstack_types.DeviceFeature.MediaPlayerPower);
|
|
49057
|
+
if (status === void 0 || status.state === void 0) return {
|
|
49058
|
+
...UNKNOWN_VIEW,
|
|
49059
|
+
canSwitchPower
|
|
49060
|
+
};
|
|
49061
|
+
const power = powerOf(status.state);
|
|
49062
|
+
const running = runningOf(status.state);
|
|
49063
|
+
const base = {
|
|
49064
|
+
...UNKNOWN_VIEW,
|
|
49065
|
+
power,
|
|
49066
|
+
running,
|
|
49067
|
+
stateAssumed: isAssumed(status, "state"),
|
|
49068
|
+
canSwitchPower
|
|
49069
|
+
};
|
|
49070
|
+
if (power !== "on") return base;
|
|
49071
|
+
const hasTransportFeature = has(_camstack_types.DeviceFeature.MediaPlayerNext) || has(_camstack_types.DeviceFeature.MediaPlayerPrevious) || has(_camstack_types.DeviceFeature.MediaPlayerStop) || has(_camstack_types.DeviceFeature.MediaPlayerSeek);
|
|
49072
|
+
const volume = has(_camstack_types.DeviceFeature.MediaPlayerVolume) ? "slider" : has(_camstack_types.DeviceFeature.MediaPlayerVolumeStep) ? "steps" : "none";
|
|
49073
|
+
const sourceName = typeof status.source === "string" ? status.source.trim() : "";
|
|
49074
|
+
const options = status.availableSources ?? [];
|
|
49075
|
+
const hasSource = sourceName !== "" || options.length > 0;
|
|
49076
|
+
return {
|
|
49077
|
+
...base,
|
|
49078
|
+
transport: {
|
|
49079
|
+
playPause: running !== "none" || hasTransportFeature,
|
|
49080
|
+
previous: has(_camstack_types.DeviceFeature.MediaPlayerPrevious),
|
|
49081
|
+
next: has(_camstack_types.DeviceFeature.MediaPlayerNext),
|
|
49082
|
+
stop: has(_camstack_types.DeviceFeature.MediaPlayerStop)
|
|
49083
|
+
},
|
|
49084
|
+
seek: has(_camstack_types.DeviceFeature.MediaPlayerSeek) && status.duration !== null && status.duration > 0,
|
|
49085
|
+
volume,
|
|
49086
|
+
volumeAssumed: isAssumed(status, "volumeLevel"),
|
|
49087
|
+
mute: has(_camstack_types.DeviceFeature.MediaPlayerMute) || volume === "slider" && status.isMuted !== null,
|
|
49088
|
+
volumeKnown: status.volumeLevel !== null,
|
|
49089
|
+
muteKnown: status.isMuted !== null,
|
|
49090
|
+
artworkUrl: artworkOf(status),
|
|
49091
|
+
muteAssumed: isAssumed(status, "isMuted"),
|
|
49092
|
+
source: hasSource ? {
|
|
49093
|
+
current: sourceName,
|
|
49094
|
+
options,
|
|
49095
|
+
selectable: has(_camstack_types.DeviceFeature.MediaPlayerSelectSource) && options.length > 1
|
|
49096
|
+
} : null,
|
|
49097
|
+
sourceAssumed: isAssumed(status, "source"),
|
|
49098
|
+
shuffle: has(_camstack_types.DeviceFeature.MediaPlayerShuffle) && status.shuffle !== null,
|
|
49099
|
+
repeat: has(_camstack_types.DeviceFeature.MediaPlayerRepeat) && status.repeat !== null
|
|
49100
|
+
};
|
|
49101
|
+
}
|
|
49102
|
+
//#endregion
|
|
48769
49103
|
//#region src/composites/device-controls/media-player-panel.tsx
|
|
48770
49104
|
/**
|
|
48771
49105
|
* Exhaustive colour map — one entry per MediaPlayerState.
|
|
48772
49106
|
* Build fails if a state is added and not reflected here.
|
|
48773
49107
|
*/
|
|
48774
49108
|
var STATE_COLOR = {
|
|
48775
|
-
playing: "border-
|
|
48776
|
-
paused: "border-
|
|
48777
|
-
buffering: "border-
|
|
48778
|
-
on: "border-
|
|
48779
|
-
idle: "border-
|
|
48780
|
-
off: "border-
|
|
48781
|
-
standby: "border-
|
|
49109
|
+
playing: "border-success/50 bg-success/10",
|
|
49110
|
+
paused: "border-warning/50 bg-warning/10",
|
|
49111
|
+
buffering: "border-info/50 bg-info/10",
|
|
49112
|
+
on: "border-foreground-subtle/40 bg-surface-hover",
|
|
49113
|
+
idle: "border-foreground-subtle/40 bg-surface-hover",
|
|
49114
|
+
off: "border-border bg-surface",
|
|
49115
|
+
standby: "border-border bg-surface"
|
|
48782
49116
|
};
|
|
48783
49117
|
/** Dot indicator colour (small circle) per state. */
|
|
48784
49118
|
var STATE_DOT_COLOR = {
|
|
48785
|
-
playing: "bg-
|
|
48786
|
-
paused: "bg-
|
|
48787
|
-
buffering: "bg-
|
|
48788
|
-
on: "bg-
|
|
48789
|
-
idle: "bg-
|
|
48790
|
-
off: "bg-
|
|
48791
|
-
standby: "bg-
|
|
49119
|
+
playing: "bg-success",
|
|
49120
|
+
paused: "bg-warning",
|
|
49121
|
+
buffering: "bg-info",
|
|
49122
|
+
on: "bg-foreground-subtle",
|
|
49123
|
+
idle: "bg-foreground-subtle",
|
|
49124
|
+
off: "bg-border",
|
|
49125
|
+
standby: "bg-border"
|
|
48792
49126
|
};
|
|
48793
49127
|
/** Exhaustive tuple of valid repeat values — single source of truth. */
|
|
48794
49128
|
var REPEAT_VALUES = [
|
|
@@ -48812,7 +49146,7 @@ function toggleAction$1(state) {
|
|
|
48812
49146
|
if (state === "playing" || state === "buffering") return "pause";
|
|
48813
49147
|
return "play";
|
|
48814
49148
|
}
|
|
48815
|
-
function MediaPlayerPanel({ trpc, deviceId, features
|
|
49149
|
+
function MediaPlayerPanel({ trpc, deviceId, features, layout, optimistic }) {
|
|
48816
49150
|
const t = useUiText();
|
|
48817
49151
|
const { cap, slice, available } = useDeviceCapability({
|
|
48818
49152
|
trpc,
|
|
@@ -48822,6 +49156,7 @@ function MediaPlayerPanel({ trpc, deviceId, features: _features, layout, optimis
|
|
|
48822
49156
|
});
|
|
48823
49157
|
const { display, applyOptimistic } = useOptimisticSlice(slice, { enabled: optimistic ?? true });
|
|
48824
49158
|
if (display === void 0) return null;
|
|
49159
|
+
const declared = deriveMediaPlayerView(display, features, {});
|
|
48825
49160
|
const busy = !available;
|
|
48826
49161
|
const action = toggleAction$1(display.state);
|
|
48827
49162
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -48876,7 +49211,7 @@ function MediaPlayerPanel({ trpc, deviceId, features: _features, layout, optimis
|
|
|
48876
49211
|
children: "⏭"
|
|
48877
49212
|
})]
|
|
48878
49213
|
}),
|
|
48879
|
-
display.volumeLevel !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
49214
|
+
(declared.volume === "slider" || display.volumeLevel !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
48880
49215
|
className: "flex items-center gap-2 text-xs text-foreground-subtle",
|
|
48881
49216
|
children: [
|
|
48882
49217
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("uiLibrary.mediaPlayerPanel.vol", "Vol") }),
|
|
@@ -48886,7 +49221,7 @@ function MediaPlayerPanel({ trpc, deviceId, features: _features, layout, optimis
|
|
|
48886
49221
|
min: 0,
|
|
48887
49222
|
max: 100,
|
|
48888
49223
|
step: 1,
|
|
48889
|
-
value: display.volumeLevel,
|
|
49224
|
+
value: display.volumeLevel ?? 0,
|
|
48890
49225
|
disabled: busy,
|
|
48891
49226
|
onChange: (e) => {
|
|
48892
49227
|
const volumeLevel = Number(e.target.value);
|
|
@@ -48894,25 +49229,25 @@ function MediaPlayerPanel({ trpc, deviceId, features: _features, layout, optimis
|
|
|
48894
49229
|
if (!busy) cap?.setVolume({ volumeLevel });
|
|
48895
49230
|
}
|
|
48896
49231
|
}),
|
|
48897
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
49232
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
48898
49233
|
className: "tabular-nums w-8 text-right",
|
|
48899
|
-
children:
|
|
49234
|
+
children: display.volumeLevel === null ? "—" : `${display.volumeLevel}%`
|
|
48900
49235
|
})
|
|
48901
49236
|
]
|
|
48902
49237
|
}),
|
|
48903
|
-
display.isMuted !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
49238
|
+
(declared.mute || display.isMuted !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
48904
49239
|
type: "button",
|
|
48905
49240
|
"aria-label": display.isMuted ? t("uiLibrary.mediaPlayerPanel.unmute", "Unmute") : t("uiLibrary.mediaPlayerPanel.mute", "Mute"),
|
|
48906
49241
|
disabled: busy,
|
|
48907
49242
|
onClick: (e) => {
|
|
48908
49243
|
e.stopPropagation();
|
|
48909
|
-
if (!busy
|
|
48910
|
-
const muted = !display.isMuted;
|
|
49244
|
+
if (!busy) {
|
|
49245
|
+
const muted = display.isMuted === null ? true : !display.isMuted;
|
|
48911
49246
|
applyOptimistic({ isMuted: muted });
|
|
48912
49247
|
cap?.setMute({ muted });
|
|
48913
49248
|
}
|
|
48914
49249
|
},
|
|
48915
|
-
className: cn("inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs transition-colors", display.isMuted ? "bg-
|
|
49250
|
+
className: cn("inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs transition-colors", display.isMuted ? "bg-warning-fill text-warning-on" : "text-foreground-subtle hover:text-foreground hover:bg-surface-hover", busy && "opacity-40 cursor-not-allowed"),
|
|
48916
49251
|
children: display.isMuted ? "🔇" : "🔊"
|
|
48917
49252
|
}),
|
|
48918
49253
|
display.availableSources.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
@@ -48951,7 +49286,7 @@ function MediaPlayerPanel({ trpc, deviceId, features: _features, layout, optimis
|
|
|
48951
49286
|
cap?.setShuffle({ shuffle });
|
|
48952
49287
|
}
|
|
48953
49288
|
},
|
|
48954
|
-
className: cn("inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs transition-colors", display.shuffle ? "bg-
|
|
49289
|
+
className: cn("inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs transition-colors", display.shuffle ? "bg-success-fill text-success-on" : "text-foreground-subtle hover:text-foreground hover:bg-surface-hover", busy && "opacity-40 cursor-not-allowed"),
|
|
48955
49290
|
children: ["⇌ ", t("uiLibrary.mediaPlayerPanel.shuffle", "Shuffle")]
|
|
48956
49291
|
}),
|
|
48957
49292
|
display.repeat !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
@@ -55595,7 +55930,7 @@ function SwingToggle({ axis, on, busy, onToggle }) {
|
|
|
55595
55930
|
* "Run N min".
|
|
55596
55931
|
* - HeaterHeroCard (device-detail hero): the glowing heat backdrop (the same
|
|
55597
55932
|
* rising streaks a heating air conditioner draws) while it is on, the
|
|
55598
|
-
* on/off switch
|
|
55933
|
+
* on/off switch and the timed
|
|
55599
55934
|
* run (number, unit, Run, countdown, Cancel).
|
|
55600
55935
|
*
|
|
55601
55936
|
* Every reading may be unknown (`null`) and is drawn as a dash, never as zero.
|
|
@@ -55617,12 +55952,6 @@ function useHeater({ trpc, deviceId, optimistic }) {
|
|
|
55617
55952
|
cap: (d) => d.runningState,
|
|
55618
55953
|
slice: (d) => d.state.runningState
|
|
55619
55954
|
});
|
|
55620
|
-
const power = useDeviceCapability({
|
|
55621
|
-
trpc,
|
|
55622
|
-
deviceId,
|
|
55623
|
-
cap: (d) => d.powerMeter,
|
|
55624
|
-
slice: (d) => d.state.powerMeter
|
|
55625
|
-
});
|
|
55626
55955
|
const timer = useDeviceCapability({
|
|
55627
55956
|
trpc,
|
|
55628
55957
|
deviceId,
|
|
@@ -55636,7 +55965,6 @@ function useHeater({ trpc, deviceId, optimistic }) {
|
|
|
55636
55965
|
available,
|
|
55637
55966
|
applyOptimistic,
|
|
55638
55967
|
running: running.slice,
|
|
55639
|
-
power: power.slice,
|
|
55640
55968
|
timer
|
|
55641
55969
|
};
|
|
55642
55970
|
}
|
|
@@ -55679,11 +56007,10 @@ function HeaterInlineControl(props) {
|
|
|
55679
56007
|
}
|
|
55680
56008
|
function HeaterHeroCard(props) {
|
|
55681
56009
|
const t = useUiText();
|
|
55682
|
-
const { cap, display, available, applyOptimistic, running,
|
|
56010
|
+
const { cap, display, available, applyOptimistic, running, timer } = useHeater(props);
|
|
55683
56011
|
if (cap === void 0 || display === void 0) return null;
|
|
55684
56012
|
const on = display.on === true;
|
|
55685
56013
|
const heating = running?.running ?? on;
|
|
55686
|
-
const watts = power?.power ?? null;
|
|
55687
56014
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55688
56015
|
className: "relative flex flex-col items-stretch gap-3 overflow-hidden rounded-lg border border-border bg-surface p-4",
|
|
55689
56016
|
children: [
|
|
@@ -55701,21 +56028,13 @@ function HeaterHeroCard(props) {
|
|
|
55701
56028
|
})
|
|
55702
56029
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
55703
56030
|
className: "relative z-10 flex flex-col items-center gap-1",
|
|
55704
|
-
children: [
|
|
55705
|
-
|
|
55706
|
-
|
|
55707
|
-
|
|
55708
|
-
|
|
55709
|
-
|
|
55710
|
-
|
|
55711
|
-
children: heating ? t("uiLibrary.heater.heating", "Heating") : t("uiLibrary.heater.off", "Off")
|
|
55712
|
-
}),
|
|
55713
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
55714
|
-
className: "text-xs tabular-nums text-foreground-muted",
|
|
55715
|
-
"data-testid": "heater-watts",
|
|
55716
|
-
children: watts === null ? "—" : `${Math.round(watts)} W`
|
|
55717
|
-
})
|
|
55718
|
-
]
|
|
56031
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Flame, {
|
|
56032
|
+
className: cn("h-8 w-8", heating ? "text-warning" : "text-foreground-subtle"),
|
|
56033
|
+
"aria-hidden": true
|
|
56034
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56035
|
+
className: "text-sm font-medium text-foreground",
|
|
56036
|
+
children: heating ? t("uiLibrary.heater.heating", "Heating") : t("uiLibrary.heater.off", "Off")
|
|
56037
|
+
})]
|
|
55719
56038
|
})]
|
|
55720
56039
|
}),
|
|
55721
56040
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
@@ -56160,17 +56479,16 @@ function DishwasherHeroCard(props) {
|
|
|
56160
56479
|
* Appliance card for a `DeviceType.Washer` / `DeviceType.Dryer` device.
|
|
56161
56480
|
*
|
|
56162
56481
|
* These appliances have no program surface: what is worth showing is whether
|
|
56163
|
-
* the cycle is running (the `running-state` cap)
|
|
56164
|
-
*
|
|
56165
|
-
*
|
|
56482
|
+
* the cycle is running (the `running-state` cap) and for how long. The draw
|
|
56483
|
+
* is NOT drawn here: the `power-meter` cap's hero widget shows it under every
|
|
56484
|
+
* hero card (D1004).
|
|
56166
56485
|
* - ApplianceInlineControl (device-list row): the running badge round the
|
|
56167
|
-
* drum icon
|
|
56486
|
+
* drum icon.
|
|
56168
56487
|
* - ApplianceHeroCard (device-detail hero): the drum (turning only while a
|
|
56169
|
-
* cycle runs), the state, the phase
|
|
56488
|
+
* cycle runs), the state, the phase and the dwell.
|
|
56170
56489
|
*
|
|
56171
56490
|
* UNKNOWN IS NOT OFF (D393). `running: null` is drawn as "Unknown" and the
|
|
56172
|
-
* drum stays still and unbadged
|
|
56173
|
-
* "0 W". A slice that has not landed hides its row instead of faking a value.
|
|
56491
|
+
* drum stays still and unbadged.
|
|
56174
56492
|
*/
|
|
56175
56493
|
var KEYFRAMES = `
|
|
56176
56494
|
@keyframes apl-tumble { to { transform: rotate(360deg) } }
|
|
@@ -56179,10 +56497,6 @@ var KEYFRAMES = `
|
|
|
56179
56497
|
.apl-drum-run { animation: none !important; }
|
|
56180
56498
|
}
|
|
56181
56499
|
`;
|
|
56182
|
-
/** Whole watts, or a dash when the appliance has not reported a reading. */
|
|
56183
|
-
function formatWatts(power) {
|
|
56184
|
-
return power === void 0 || !Number.isFinite(power) ? "—" : `${Math.round(power)} W`;
|
|
56185
|
-
}
|
|
56186
56500
|
/** The state to a person: running / idle, or why there is none (unknown). */
|
|
56187
56501
|
function applianceStateLabel(running, t) {
|
|
56188
56502
|
if (running === true) return {
|
|
@@ -56205,10 +56519,7 @@ function dwellText(running, since, now, t) {
|
|
|
56205
56519
|
return "minutes" in duration ? t("uiLibrary.appliance.forMinutes", "for {{count}} min", { count: duration.minutes }) : t("uiLibrary.appliance.forHours", "for {{count}} h", { count: duration.hours });
|
|
56206
56520
|
}
|
|
56207
56521
|
function useApplianceState(props) {
|
|
56208
|
-
return {
|
|
56209
|
-
running: useDeviceState(props.trpc, props.deviceId, (s) => s.runningState),
|
|
56210
|
-
power: useDeviceState(props.trpc, props.deviceId, (s) => s.powerMeter)
|
|
56211
|
-
};
|
|
56522
|
+
return { running: useDeviceState(props.trpc, props.deviceId, (s) => s.runningState) };
|
|
56212
56523
|
}
|
|
56213
56524
|
/** The drum: a ring with a few items in it, turning only while a cycle runs. */
|
|
56214
56525
|
function Drum({ running }) {
|
|
@@ -56230,7 +56541,7 @@ function Drum({ running }) {
|
|
|
56230
56541
|
}
|
|
56231
56542
|
function ApplianceHeroCard(props) {
|
|
56232
56543
|
const t = useUiText();
|
|
56233
|
-
const { running
|
|
56544
|
+
const { running } = useApplianceState(props);
|
|
56234
56545
|
const state = running?.running ?? null;
|
|
56235
56546
|
const meta = applianceStateLabel(state, t);
|
|
56236
56547
|
const phase = running?.phase?.trim() ?? "";
|
|
@@ -56242,50 +56553,35 @@ function ApplianceHeroCard(props) {
|
|
|
56242
56553
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Drum, { running: state }),
|
|
56243
56554
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56244
56555
|
className: "flex min-w-0 flex-1 flex-col gap-2",
|
|
56245
|
-
children: [
|
|
56246
|
-
|
|
56247
|
-
|
|
56248
|
-
|
|
56249
|
-
|
|
56250
|
-
|
|
56251
|
-
|
|
56252
|
-
|
|
56253
|
-
|
|
56254
|
-
|
|
56255
|
-
|
|
56256
|
-
|
|
56257
|
-
phase
|
|
56258
|
-
|
|
56259
|
-
children: phase
|
|
56260
|
-
}),
|
|
56261
|
-
power !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
56262
|
-
"data-testid": "appliance-power",
|
|
56263
|
-
className: "inline-flex items-center gap-1 text-sm tabular-nums text-foreground-muted",
|
|
56264
|
-
title: power.power === void 0 ? t("uiLibrary.appliance.powerUnknown", "Power unknown") : void 0,
|
|
56265
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Zap, {
|
|
56266
|
-
className: "h-3.5 w-3.5",
|
|
56267
|
-
"aria-hidden": true
|
|
56268
|
-
}), formatWatts(power.power)]
|
|
56269
|
-
})
|
|
56270
|
-
]
|
|
56556
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
56557
|
+
className: "flex flex-wrap items-baseline gap-x-2",
|
|
56558
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56559
|
+
"data-testid": "appliance-state",
|
|
56560
|
+
className: cn("text-3xl font-semibold", meta.tone),
|
|
56561
|
+
children: meta.label
|
|
56562
|
+
}), dwell !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56563
|
+
className: "text-sm tabular-nums text-foreground-subtle",
|
|
56564
|
+
children: dwell
|
|
56565
|
+
})]
|
|
56566
|
+
}), phase !== "" && state !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
56567
|
+
className: "text-sm text-foreground-subtle",
|
|
56568
|
+
children: phase
|
|
56569
|
+
})]
|
|
56271
56570
|
})
|
|
56272
56571
|
]
|
|
56273
56572
|
});
|
|
56274
56573
|
}
|
|
56275
56574
|
function ApplianceInlineControl(props) {
|
|
56276
|
-
const { running
|
|
56277
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
56575
|
+
const { running } = useApplianceState(props);
|
|
56576
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
56278
56577
|
className: "inline-flex items-center gap-1.5 max-w-full",
|
|
56279
|
-
children:
|
|
56578
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RunningBadge, {
|
|
56280
56579
|
running: running?.running ?? null,
|
|
56281
56580
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WashingMachine, {
|
|
56282
56581
|
className: "h-4 w-4 text-foreground-muted",
|
|
56283
56582
|
"aria-hidden": true
|
|
56284
56583
|
})
|
|
56285
|
-
})
|
|
56286
|
-
className: "text-xs tabular-nums text-foreground-subtle",
|
|
56287
|
-
children: formatWatts(power.power)
|
|
56288
|
-
})]
|
|
56584
|
+
})
|
|
56289
56585
|
});
|
|
56290
56586
|
}
|
|
56291
56587
|
//#endregion
|
|
@@ -57250,6 +57546,106 @@ function SwitchHeroCard({ trpc, deviceId, optimistic }) {
|
|
|
57250
57546
|
});
|
|
57251
57547
|
}
|
|
57252
57548
|
//#endregion
|
|
57549
|
+
//#region src/composites/device-controls/media-player-hero-parts.tsx
|
|
57550
|
+
/**
|
|
57551
|
+
* The animated parts of the media-player hero: the power orb and the running
|
|
57552
|
+
* indicator. Motion is transform / opacity only, plays only while the state
|
|
57553
|
+
* says so, and stops under `prefers-reduced-motion` (the state is still told
|
|
57554
|
+
* by colour, icon and text, never by motion alone).
|
|
57555
|
+
*/
|
|
57556
|
+
var MEDIA_HERO_KEYFRAMES = `
|
|
57557
|
+
@keyframes mph-eq { 0%, 100% { transform: scaleY(.3) } 50% { transform: scaleY(1) } }
|
|
57558
|
+
@keyframes mph-halo { 0% { transform: scale(.92); opacity: .55 } 100% { transform: scale(1.4); opacity: 0 } }
|
|
57559
|
+
.mph-eq { transform-origin: bottom; animation: mph-eq 1s ease-in-out infinite; }
|
|
57560
|
+
.mph-eq:nth-child(2) { animation-duration: .8s; animation-delay: -.3s; }
|
|
57561
|
+
.mph-eq:nth-child(3) { animation-duration: 1.2s; animation-delay: -.6s; }
|
|
57562
|
+
.mph-eq:nth-child(4) { animation-duration: .9s; animation-delay: -.1s; }
|
|
57563
|
+
.mph-halo { animation: mph-halo 2.8s ease-out infinite; }
|
|
57564
|
+
@keyframes mph-in { from { opacity: 0 } to { opacity: 1 } }
|
|
57565
|
+
@keyframes mph-out { from { opacity: 1 } to { opacity: 0 } }
|
|
57566
|
+
.mph-fade-in { animation: mph-in .6s ease-out both; }
|
|
57567
|
+
.mph-fade-out { animation: mph-out .6s ease-out both; }
|
|
57568
|
+
@media (prefers-reduced-motion: reduce) {
|
|
57569
|
+
.mph-eq, .mph-halo, .mph-fade-in, .mph-fade-out { animation: none !important; }
|
|
57570
|
+
.mph-fade-out { opacity: 0; }
|
|
57571
|
+
.mph-eq:nth-child(odd) { transform: scaleY(.6); }
|
|
57572
|
+
.mph-halo { opacity: 0; }
|
|
57573
|
+
}
|
|
57574
|
+
`;
|
|
57575
|
+
var ORB_TONE = {
|
|
57576
|
+
on: "border-success bg-success/15 text-success shadow-lg shadow-success/30",
|
|
57577
|
+
standby: "border-warning bg-warning/10 text-warning",
|
|
57578
|
+
off: "border-border bg-surface-hover text-foreground-subtle",
|
|
57579
|
+
unknown: "border-dashed border-border bg-transparent text-foreground-subtle"
|
|
57580
|
+
};
|
|
57581
|
+
/** The device's power: a glowing ring when on, amber in standby, flat when off, dashed when unknown. */
|
|
57582
|
+
function PowerOrb({ power, onPress, label, busy }) {
|
|
57583
|
+
const body = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: power === "unknown" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CircleQuestionMark, {
|
|
57584
|
+
className: "h-7 w-7",
|
|
57585
|
+
"aria-hidden": "true"
|
|
57586
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Power, {
|
|
57587
|
+
className: "h-7 w-7",
|
|
57588
|
+
"aria-hidden": "true"
|
|
57589
|
+
}) });
|
|
57590
|
+
const classes = cn("relative z-10 inline-flex h-16 w-16 items-center justify-center rounded-full border-2", "transition-all duration-500 motion-reduce:transition-none", ORB_TONE[power]);
|
|
57591
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57592
|
+
className: "relative flex h-20 w-20 items-center justify-center",
|
|
57593
|
+
"data-power": power,
|
|
57594
|
+
children: [power === "on" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57595
|
+
"aria-hidden": "true",
|
|
57596
|
+
"data-testid": "media-power-halo",
|
|
57597
|
+
className: "mph-halo absolute h-16 w-16 rounded-full bg-success/25"
|
|
57598
|
+
}), onPress === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57599
|
+
className: classes,
|
|
57600
|
+
"data-testid": "media-power",
|
|
57601
|
+
role: "img",
|
|
57602
|
+
"aria-label": label,
|
|
57603
|
+
children: body
|
|
57604
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57605
|
+
type: "button",
|
|
57606
|
+
"aria-label": label,
|
|
57607
|
+
title: label,
|
|
57608
|
+
disabled: busy,
|
|
57609
|
+
"data-testid": "media-power",
|
|
57610
|
+
onClick: (e) => {
|
|
57611
|
+
e.stopPropagation();
|
|
57612
|
+
if (!busy) onPress();
|
|
57613
|
+
},
|
|
57614
|
+
className: cn(classes, "hover:brightness-110 active:scale-95", busy && "cursor-not-allowed opacity-40"),
|
|
57615
|
+
children: body
|
|
57616
|
+
})]
|
|
57617
|
+
});
|
|
57618
|
+
}
|
|
57619
|
+
var EQ_BARS = [
|
|
57620
|
+
0,
|
|
57621
|
+
1,
|
|
57622
|
+
2,
|
|
57623
|
+
3
|
|
57624
|
+
];
|
|
57625
|
+
/** Equalizer while playing, a spinner while buffering, a pause glyph when paused; nothing otherwise. */
|
|
57626
|
+
function RunningIndicator({ running }) {
|
|
57627
|
+
if (running === "playing") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57628
|
+
className: "inline-flex h-4 items-end gap-0.5 text-primary",
|
|
57629
|
+
"data-testid": "media-running",
|
|
57630
|
+
"data-running": "playing",
|
|
57631
|
+
"aria-hidden": "true",
|
|
57632
|
+
children: EQ_BARS.map((bar) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "mph-eq h-4 w-1 rounded-full bg-primary" }, bar))
|
|
57633
|
+
});
|
|
57634
|
+
if (running === "buffering") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoaderCircle, {
|
|
57635
|
+
className: "h-4 w-4 animate-spin text-foreground-muted motion-reduce:animate-none",
|
|
57636
|
+
"data-testid": "media-running",
|
|
57637
|
+
"data-running": "buffering",
|
|
57638
|
+
"aria-hidden": "true"
|
|
57639
|
+
});
|
|
57640
|
+
if (running === "paused") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pause, {
|
|
57641
|
+
className: "h-4 w-4 text-foreground-muted",
|
|
57642
|
+
"data-testid": "media-running",
|
|
57643
|
+
"data-running": "paused",
|
|
57644
|
+
"aria-hidden": "true"
|
|
57645
|
+
});
|
|
57646
|
+
return null;
|
|
57647
|
+
}
|
|
57648
|
+
//#endregion
|
|
57253
57649
|
//#region src/composites/device-controls/media-player-hero-card.tsx
|
|
57254
57650
|
/** Which states map to play() vs pause() on the central transport button. */
|
|
57255
57651
|
function toggleAction(state) {
|
|
@@ -57266,12 +57662,50 @@ function formatClock(ms) {
|
|
|
57266
57662
|
const total = Math.floor(ms / 1e3);
|
|
57267
57663
|
return `${Math.floor(total / 60)}:${(total % 60).toString().padStart(2, "0")}`;
|
|
57268
57664
|
}
|
|
57269
|
-
|
|
57665
|
+
var NEXT_REPEAT = {
|
|
57666
|
+
off: "all",
|
|
57667
|
+
all: "one",
|
|
57668
|
+
one: "off"
|
|
57669
|
+
};
|
|
57670
|
+
/** The artwork of what is playing; a change cross-fades from the previous cover. */
|
|
57671
|
+
function Artwork({ url }) {
|
|
57672
|
+
const [shown, setShown] = (0, react$1.useState)(url);
|
|
57673
|
+
const [previous, setPrevious] = (0, react$1.useState)(null);
|
|
57674
|
+
const [failed, setFailed] = (0, react$1.useState)(null);
|
|
57675
|
+
const last = (0, react$1.useRef)(url);
|
|
57676
|
+
(0, react$1.useEffect)(() => {
|
|
57677
|
+
if (last.current === url) return;
|
|
57678
|
+
setPrevious(last.current);
|
|
57679
|
+
setShown(url);
|
|
57680
|
+
last.current = url;
|
|
57681
|
+
const timer = setTimeout(() => setPrevious(null), 700);
|
|
57682
|
+
return () => clearTimeout(timer);
|
|
57683
|
+
}, [url]);
|
|
57684
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57685
|
+
"data-testid": "media-artwork",
|
|
57686
|
+
className: "relative h-40 w-40 overflow-hidden rounded-lg border border-border bg-surface-hover",
|
|
57687
|
+
children: [previous !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
57688
|
+
src: previous,
|
|
57689
|
+
alt: "",
|
|
57690
|
+
className: "mph-fade-out absolute inset-0 h-full w-full object-cover"
|
|
57691
|
+
}), shown !== null && failed !== shown ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
57692
|
+
src: shown,
|
|
57693
|
+
alt: "",
|
|
57694
|
+
"data-testid": "media-artwork-img",
|
|
57695
|
+
className: "mph-fade-in absolute inset-0 h-full w-full object-cover",
|
|
57696
|
+
onError: () => setFailed(shown)
|
|
57697
|
+
}, shown) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Music, {
|
|
57698
|
+
className: "absolute inset-0 m-auto h-8 w-8 text-foreground-subtle",
|
|
57699
|
+
"aria-hidden": "true"
|
|
57700
|
+
})]
|
|
57701
|
+
});
|
|
57702
|
+
}
|
|
57703
|
+
function NowPlaying({ title, subtitle, artworkUrl }) {
|
|
57270
57704
|
const t = useUiText();
|
|
57271
57705
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57272
|
-
className: "flex flex-col items-center gap-
|
|
57706
|
+
className: "flex flex-col items-center gap-2 text-center",
|
|
57273
57707
|
children: [
|
|
57274
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Music, {
|
|
57708
|
+
artworkUrl !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Artwork, { url: artworkUrl }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Music, {
|
|
57275
57709
|
className: "h-6 w-6 text-foreground-subtle",
|
|
57276
57710
|
"aria-hidden": "true"
|
|
57277
57711
|
}),
|
|
@@ -57286,33 +57720,77 @@ function NowPlaying({ title, subtitle }) {
|
|
|
57286
57720
|
]
|
|
57287
57721
|
});
|
|
57288
57722
|
}
|
|
57289
|
-
|
|
57723
|
+
var STATE_LABEL$1 = {
|
|
57724
|
+
off: "Off",
|
|
57725
|
+
on: "On",
|
|
57726
|
+
idle: "Idle",
|
|
57727
|
+
playing: "Playing",
|
|
57728
|
+
paused: "Paused",
|
|
57729
|
+
buffering: "Buffering",
|
|
57730
|
+
standby: "Standby"
|
|
57731
|
+
};
|
|
57732
|
+
function StateLine({ state, assumed, source, running }) {
|
|
57733
|
+
const t = useUiText();
|
|
57734
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57735
|
+
className: "flex flex-wrap items-center justify-center gap-2 text-xs text-foreground-muted",
|
|
57736
|
+
"data-testid": "media-state",
|
|
57737
|
+
children: [
|
|
57738
|
+
running,
|
|
57739
|
+
state === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57740
|
+
className: "font-medium text-foreground-subtle",
|
|
57741
|
+
"data-testid": "media-state-unknown",
|
|
57742
|
+
children: t("uiLibrary.mediaPlayerHero.state.unknown", "State unknown")
|
|
57743
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57744
|
+
className: "font-medium text-foreground",
|
|
57745
|
+
children: t(`uiLibrary.mediaPlayerHero.state.${state}`, STATE_LABEL$1[state])
|
|
57746
|
+
}),
|
|
57747
|
+
assumed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57748
|
+
className: "rounded border border-dashed border-border px-1.5 py-0.5 text-[11px] text-foreground-subtle",
|
|
57749
|
+
title: t("uiLibrary.mediaPlayerHero.assumedHint", "No feedback from the device: this is what was last sent."),
|
|
57750
|
+
"data-testid": "media-assumed",
|
|
57751
|
+
children: t("uiLibrary.mediaPlayerHero.assumed", "assumed")
|
|
57752
|
+
}),
|
|
57753
|
+
source !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57754
|
+
"data-testid": "media-source",
|
|
57755
|
+
children: source
|
|
57756
|
+
})
|
|
57757
|
+
]
|
|
57758
|
+
});
|
|
57759
|
+
}
|
|
57760
|
+
function TransportButton({ label, busy, onPress, children, primary, active, testId }) {
|
|
57290
57761
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57291
57762
|
type: "button",
|
|
57292
57763
|
"aria-label": label,
|
|
57764
|
+
"aria-pressed": active,
|
|
57293
57765
|
title: label,
|
|
57294
57766
|
disabled: busy,
|
|
57767
|
+
"data-testid": testId,
|
|
57295
57768
|
onClick: (e) => {
|
|
57296
57769
|
e.stopPropagation();
|
|
57297
57770
|
if (!busy) onPress();
|
|
57298
57771
|
},
|
|
57299
|
-
className: cn("inline-flex items-center justify-center rounded-full transition-colors", primary ? "h-12 w-12 bg-primary text-primary-foreground hover:bg-primary/90 shadow-md" : "h-10 w-10 text-foreground-muted hover:bg-surface-hover", busy && "opacity-40 cursor-not-allowed"),
|
|
57772
|
+
className: cn("inline-flex items-center justify-center rounded-full transition-colors", primary ? "h-12 w-12 bg-primary text-primary-foreground hover:bg-primary/90 shadow-md" : "h-10 w-10 text-foreground-muted hover:bg-surface-hover", active === true && "bg-primary/15 text-primary", busy && "opacity-40 cursor-not-allowed"),
|
|
57300
57773
|
children
|
|
57301
57774
|
});
|
|
57302
57775
|
}
|
|
57303
57776
|
/**
|
|
57304
|
-
* MediaPlayerHeroCard —
|
|
57777
|
+
* MediaPlayerHeroCard — the state of a MediaPlayer device and every control it
|
|
57778
|
+
* exposes, drawn from `deriveMediaPlayerView` (the state → view mapping and
|
|
57779
|
+
* its spec live in `media-player-view.ts`).
|
|
57305
57780
|
*
|
|
57306
|
-
*
|
|
57307
|
-
*
|
|
57308
|
-
*
|
|
57309
|
-
*
|
|
57310
|
-
*
|
|
57311
|
-
*
|
|
57312
|
-
*
|
|
57313
|
-
*
|
|
57781
|
+
* - Power orb: glowing when on, amber in standby, flat when off, dashed with a
|
|
57782
|
+
* question mark while the state is unknown (never drawn as off). It is the
|
|
57783
|
+
* power switch when the device declares `MediaPlayerPower`.
|
|
57784
|
+
* - Running line: equalizer while playing, spinner while buffering, pause
|
|
57785
|
+
* glyph when paused; a value the driver only guesses carries an "assumed" mark.
|
|
57786
|
+
* - Only while the device is on: now-playing, seek, transport (previous /
|
|
57787
|
+
* play-pause / stop / next), volume (slider with mute, or steps when the
|
|
57788
|
+
* device has no level reading), the source (a picker when it can switch),
|
|
57789
|
+
* shuffle and repeat. Each appears only when the status fills it or a
|
|
57790
|
+
* `DeviceFeature` declares it — no per-vendor list.
|
|
57314
57791
|
*
|
|
57315
57792
|
* Cap-gated on `media-player` — returns null when the device lacks the cap.
|
|
57793
|
+
* Motion respects `prefers-reduced-motion`.
|
|
57316
57794
|
*/
|
|
57317
57795
|
function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
57318
57796
|
const t = useUiText();
|
|
@@ -57323,14 +57801,24 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57323
57801
|
slice: (d) => d.state.mediaPlayer
|
|
57324
57802
|
});
|
|
57325
57803
|
const { display, applyOptimistic } = useOptimisticSlice(slice, { enabled: optimistic ?? true });
|
|
57804
|
+
const runningSlice = useDeviceState(trpc, deviceId, (st) => st.runningState);
|
|
57326
57805
|
if (cap === void 0) return null;
|
|
57327
|
-
|
|
57806
|
+
const view = deriveMediaPlayerView(display, features, { running: runningSlice?.running });
|
|
57328
57807
|
const busy = !available;
|
|
57329
|
-
const
|
|
57330
|
-
const
|
|
57331
|
-
const
|
|
57332
|
-
const
|
|
57333
|
-
|
|
57808
|
+
const status = display;
|
|
57809
|
+
const powered = status !== void 0 && view.power === "on";
|
|
57810
|
+
const action = toggleAction(status?.state ?? "off");
|
|
57811
|
+
const switchPower = () => {
|
|
57812
|
+
if (busy) return;
|
|
57813
|
+
if (view.power === "on") {
|
|
57814
|
+
applyOptimistic({ state: "off" });
|
|
57815
|
+
cap.turnOff({});
|
|
57816
|
+
} else {
|
|
57817
|
+
applyOptimistic({ state: "on" });
|
|
57818
|
+
cap.turnOn({});
|
|
57819
|
+
}
|
|
57820
|
+
};
|
|
57821
|
+
const powerLabel = powerLabelOf(view.power, t);
|
|
57334
57822
|
const handleToggle = () => {
|
|
57335
57823
|
if (busy) return;
|
|
57336
57824
|
if (action === "play") {
|
|
@@ -57341,17 +57829,60 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57341
57829
|
cap.pause({});
|
|
57342
57830
|
}
|
|
57343
57831
|
};
|
|
57344
|
-
const
|
|
57345
|
-
const
|
|
57346
|
-
const
|
|
57832
|
+
const title = status?.currentMedia?.title ?? null;
|
|
57833
|
+
const subtitle = status?.currentMedia?.artist ?? status?.currentMedia?.album ?? null;
|
|
57834
|
+
const hasNowPlaying = powered && (title !== null || subtitle !== null || view.artworkUrl !== null);
|
|
57835
|
+
const assumedAny = view.stateAssumed || view.volumeAssumed || view.muteAssumed || view.sourceAssumed;
|
|
57836
|
+
const sourceText = powered && view.source !== null && !view.source.selectable ? view.source.current : "";
|
|
57837
|
+
const volumeLevel = status?.volumeLevel ?? null;
|
|
57347
57838
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57348
|
-
className: "flex flex-col items-stretch gap-4 rounded-lg border
|
|
57839
|
+
className: cn("flex flex-col items-stretch gap-4 rounded-lg border bg-surface p-6", "transition-colors duration-500 motion-reduce:transition-none", view.power === "on" ? "border-success/40" : "border-border"),
|
|
57840
|
+
"data-testid": "media-hero",
|
|
57841
|
+
"data-power": view.power,
|
|
57349
57842
|
children: [
|
|
57350
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
57351
|
-
|
|
57352
|
-
|
|
57843
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: MEDIA_HERO_KEYFRAMES }),
|
|
57844
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57845
|
+
className: "flex flex-col items-center gap-2",
|
|
57846
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PowerOrb, {
|
|
57847
|
+
power: view.power,
|
|
57848
|
+
label: powerLabel,
|
|
57849
|
+
busy,
|
|
57850
|
+
onPress: view.canSwitchPower ? switchPower : void 0
|
|
57851
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StateLine, {
|
|
57852
|
+
state: status?.state,
|
|
57853
|
+
assumed: assumedAny,
|
|
57854
|
+
source: sourceText,
|
|
57855
|
+
running: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RunningIndicator, { running: view.running })
|
|
57856
|
+
})]
|
|
57857
|
+
}),
|
|
57858
|
+
hasNowPlaying && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NowPlaying, {
|
|
57859
|
+
title,
|
|
57860
|
+
subtitle,
|
|
57861
|
+
artworkUrl: view.artworkUrl
|
|
57862
|
+
}),
|
|
57863
|
+
powered && view.source !== null && view.source.selectable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57864
|
+
"data-testid": "media-source-select",
|
|
57865
|
+
className: "flex items-center gap-2",
|
|
57866
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57867
|
+
className: "text-xs text-foreground-subtle",
|
|
57868
|
+
children: t("uiLibrary.mediaPlayerHero.source", "Source")
|
|
57869
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Select, {
|
|
57870
|
+
"aria-label": t("uiLibrary.mediaPlayerHero.source", "Source"),
|
|
57871
|
+
value: view.source.current,
|
|
57872
|
+
disabled: busy,
|
|
57873
|
+
wrapperClassName: "relative min-w-0 flex-1",
|
|
57874
|
+
options: view.source.options.map((o) => ({
|
|
57875
|
+
value: o,
|
|
57876
|
+
label: o
|
|
57877
|
+
})),
|
|
57878
|
+
onChange: (e) => {
|
|
57879
|
+
if (busy) return;
|
|
57880
|
+
applyOptimistic({ source: e.target.value });
|
|
57881
|
+
cap.selectSource({ source: e.target.value });
|
|
57882
|
+
}
|
|
57883
|
+
})]
|
|
57353
57884
|
}),
|
|
57354
|
-
|
|
57885
|
+
powered && view.seek && status !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57355
57886
|
"data-testid": "media-seek",
|
|
57356
57887
|
className: "flex flex-col gap-1",
|
|
57357
57888
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
@@ -57365,10 +57896,10 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57365
57896
|
"aria-label": t("uiLibrary.mediaPlayerHero.seek", "Seek"),
|
|
57366
57897
|
type: "range",
|
|
57367
57898
|
min: 0,
|
|
57368
|
-
max:
|
|
57899
|
+
max: status.duration ?? 0,
|
|
57369
57900
|
step: 1e3,
|
|
57370
57901
|
className: "absolute inset-0 h-4 w-full cursor-pointer opacity-0",
|
|
57371
|
-
value:
|
|
57902
|
+
value: status.position ?? 0,
|
|
57372
57903
|
disabled: busy,
|
|
57373
57904
|
onChange: (e) => {
|
|
57374
57905
|
if (busy) return;
|
|
@@ -57379,18 +57910,19 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57379
57910
|
}),
|
|
57380
57911
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57381
57912
|
className: "pointer-events-none",
|
|
57382
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GripTrack, { fraction:
|
|
57913
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GripTrack, { fraction: progressFraction(status.position, status.duration) })
|
|
57383
57914
|
})
|
|
57384
57915
|
]
|
|
57385
57916
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57386
57917
|
className: "flex justify-between text-[11px] tabular-nums text-foreground-subtle",
|
|
57387
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatClock(
|
|
57918
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatClock(status.position) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatClock(status.duration) })]
|
|
57388
57919
|
})]
|
|
57389
57920
|
}),
|
|
57390
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57921
|
+
powered && view.transport.playPause && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57391
57922
|
className: "flex items-center justify-center gap-4",
|
|
57923
|
+
"data-testid": "media-transport",
|
|
57392
57924
|
children: [
|
|
57393
|
-
|
|
57925
|
+
view.transport.previous && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransportButton, {
|
|
57394
57926
|
label: t("uiLibrary.mediaPlayerHero.previous", "Previous"),
|
|
57395
57927
|
busy,
|
|
57396
57928
|
onPress: () => void cap.previous({}),
|
|
@@ -57412,7 +57944,16 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57412
57944
|
"aria-hidden": "true"
|
|
57413
57945
|
})
|
|
57414
57946
|
}),
|
|
57415
|
-
|
|
57947
|
+
view.transport.stop && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransportButton, {
|
|
57948
|
+
label: t("uiLibrary.mediaPlayerHero.stop", "Stop"),
|
|
57949
|
+
busy,
|
|
57950
|
+
onPress: () => void cap.stop({}),
|
|
57951
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Square, {
|
|
57952
|
+
className: "h-4 w-4",
|
|
57953
|
+
"aria-hidden": "true"
|
|
57954
|
+
})
|
|
57955
|
+
}),
|
|
57956
|
+
view.transport.next && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransportButton, {
|
|
57416
57957
|
label: t("uiLibrary.mediaPlayerHero.next", "Next"),
|
|
57417
57958
|
busy,
|
|
57418
57959
|
onPress: () => void cap.next({}),
|
|
@@ -57423,24 +57964,24 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57423
57964
|
})
|
|
57424
57965
|
]
|
|
57425
57966
|
}),
|
|
57426
|
-
|
|
57967
|
+
powered && view.volume === "slider" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57427
57968
|
"data-testid": "media-volume",
|
|
57428
57969
|
className: "flex items-center gap-2",
|
|
57429
57970
|
children: [
|
|
57430
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57971
|
+
view.mute && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
57431
57972
|
type: "button",
|
|
57432
|
-
"aria-label":
|
|
57433
|
-
title:
|
|
57973
|
+
"aria-label": status?.isMuted === true ? t("uiLibrary.mediaPlayerHero.unmute", "Unmute") : t("uiLibrary.mediaPlayerHero.mute", "Mute"),
|
|
57974
|
+
title: status?.isMuted === true ? t("uiLibrary.mediaPlayerHero.unmute", "Unmute") : t("uiLibrary.mediaPlayerHero.mute", "Mute"),
|
|
57434
57975
|
disabled: busy,
|
|
57435
57976
|
onClick: (e) => {
|
|
57436
57977
|
e.stopPropagation();
|
|
57437
|
-
if (busy
|
|
57438
|
-
const muted = !
|
|
57978
|
+
if (busy) return;
|
|
57979
|
+
const muted = status?.isMuted === null || status === void 0 ? true : !status.isMuted;
|
|
57439
57980
|
applyOptimistic({ isMuted: muted });
|
|
57440
57981
|
cap.setMute({ muted });
|
|
57441
57982
|
},
|
|
57442
57983
|
className: cn("inline-flex h-7 w-7 items-center justify-center rounded text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors", busy && "opacity-40 cursor-not-allowed"),
|
|
57443
|
-
children:
|
|
57984
|
+
children: status?.isMuted === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VolumeX, {
|
|
57444
57985
|
className: "h-4 w-4",
|
|
57445
57986
|
"aria-hidden": "true"
|
|
57446
57987
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Volume2, {
|
|
@@ -57462,7 +58003,7 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57462
58003
|
max: 100,
|
|
57463
58004
|
step: 1,
|
|
57464
58005
|
className: "absolute inset-0 h-4 w-full cursor-pointer opacity-0",
|
|
57465
|
-
value: volumeLevel,
|
|
58006
|
+
value: volumeLevel ?? 0,
|
|
57466
58007
|
disabled: busy,
|
|
57467
58008
|
onChange: (e) => {
|
|
57468
58009
|
if (busy) return;
|
|
@@ -57473,19 +58014,92 @@ function MediaPlayerHeroCard({ trpc, deviceId, features, optimistic }) {
|
|
|
57473
58014
|
}),
|
|
57474
58015
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
57475
58016
|
className: "pointer-events-none",
|
|
57476
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
58017
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
58018
|
+
className: cn(volumeLevel === null && "opacity-40"),
|
|
58019
|
+
"data-testid": "media-volume-track",
|
|
58020
|
+
"data-known": volumeLevel !== null,
|
|
58021
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GripTrack, { fraction: status?.isMuted === true || volumeLevel === null ? 0 : volumeLevel / 100 })
|
|
58022
|
+
})
|
|
57477
58023
|
})
|
|
57478
58024
|
]
|
|
57479
58025
|
}),
|
|
57480
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
58026
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
57481
58027
|
className: "w-9 text-right text-[11px] tabular-nums text-foreground-subtle",
|
|
57482
|
-
children:
|
|
58028
|
+
children: volumeLevel === null ? "—" : `${volumeLevel}%`
|
|
57483
58029
|
})
|
|
57484
58030
|
]
|
|
58031
|
+
}),
|
|
58032
|
+
powered && view.volume === "steps" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58033
|
+
"data-testid": "media-volume-steps",
|
|
58034
|
+
className: "flex items-center justify-center gap-3 text-xs text-foreground-subtle",
|
|
58035
|
+
children: [
|
|
58036
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransportButton, {
|
|
58037
|
+
label: t("uiLibrary.mediaPlayerHero.volumeDown", "Volume down"),
|
|
58038
|
+
busy,
|
|
58039
|
+
onPress: () => void cap.volumeDown({ steps: 1 }),
|
|
58040
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Minus, {
|
|
58041
|
+
className: "h-4 w-4",
|
|
58042
|
+
"aria-hidden": "true"
|
|
58043
|
+
})
|
|
58044
|
+
}),
|
|
58045
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Volume2, {
|
|
58046
|
+
className: "h-4 w-4",
|
|
58047
|
+
"aria-hidden": "true"
|
|
58048
|
+
}),
|
|
58049
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransportButton, {
|
|
58050
|
+
label: t("uiLibrary.mediaPlayerHero.volumeUp", "Volume up"),
|
|
58051
|
+
busy,
|
|
58052
|
+
onPress: () => void cap.volumeUp({ steps: 1 }),
|
|
58053
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Plus, {
|
|
58054
|
+
className: "h-4 w-4",
|
|
58055
|
+
"aria-hidden": "true"
|
|
58056
|
+
})
|
|
58057
|
+
})
|
|
58058
|
+
]
|
|
58059
|
+
}),
|
|
58060
|
+
powered && status !== void 0 && (view.shuffle || view.repeat) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
58061
|
+
className: "flex items-center justify-center gap-2",
|
|
58062
|
+
"data-testid": "media-modes",
|
|
58063
|
+
children: [view.shuffle && status.shuffle !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransportButton, {
|
|
58064
|
+
label: t("uiLibrary.mediaPlayerHero.shuffle", "Shuffle"),
|
|
58065
|
+
busy,
|
|
58066
|
+
active: status.shuffle,
|
|
58067
|
+
onPress: () => {
|
|
58068
|
+
const shuffle = !status.shuffle;
|
|
58069
|
+
applyOptimistic({ shuffle });
|
|
58070
|
+
cap.setShuffle({ shuffle });
|
|
58071
|
+
},
|
|
58072
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Shuffle, {
|
|
58073
|
+
className: "h-4 w-4",
|
|
58074
|
+
"aria-hidden": "true"
|
|
58075
|
+
})
|
|
58076
|
+
}), view.repeat && status.repeat !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransportButton, {
|
|
58077
|
+
label: t("uiLibrary.mediaPlayerHero.repeat", "Repeat"),
|
|
58078
|
+
busy,
|
|
58079
|
+
active: status.repeat !== "off",
|
|
58080
|
+
onPress: () => {
|
|
58081
|
+
if (status.repeat === null) return;
|
|
58082
|
+
const repeat = NEXT_REPEAT[status.repeat];
|
|
58083
|
+
applyOptimistic({ repeat });
|
|
58084
|
+
cap.setRepeat({ repeat });
|
|
58085
|
+
},
|
|
58086
|
+
children: status.repeat === "one" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Repeat1, {
|
|
58087
|
+
className: "h-4 w-4",
|
|
58088
|
+
"aria-hidden": "true"
|
|
58089
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Repeat, {
|
|
58090
|
+
className: "h-4 w-4",
|
|
58091
|
+
"aria-hidden": "true"
|
|
58092
|
+
})
|
|
58093
|
+
})]
|
|
57485
58094
|
})
|
|
57486
58095
|
]
|
|
57487
58096
|
});
|
|
57488
58097
|
}
|
|
58098
|
+
function powerLabelOf(power, t) {
|
|
58099
|
+
if (power === "on") return t("uiLibrary.mediaPlayerHero.turnOff", "Turn off");
|
|
58100
|
+
if (power === "unknown") return t("uiLibrary.mediaPlayerHero.powerUnknown", "Power state unknown");
|
|
58101
|
+
return t("uiLibrary.mediaPlayerHero.turnOn", "Turn on");
|
|
58102
|
+
}
|
|
57489
58103
|
//#endregion
|
|
57490
58104
|
//#region src/composites/device-controls/alarm-hero-card.tsx
|
|
57491
58105
|
var ALARM_STATE_CONFIG = {
|
|
@@ -73059,7 +73673,7 @@ function TimelineSlider({ markers, bands = [], selectedId = null, step = 5, aria
|
|
|
73059
73673
|
}
|
|
73060
73674
|
//#endregion
|
|
73061
73675
|
//#region src/ui-library-version.ts
|
|
73062
|
-
var uiLibraryVersion = "1.2.
|
|
73676
|
+
var uiLibraryVersion = "1.2.377";
|
|
73063
73677
|
//#endregion
|
|
73064
73678
|
//#region src/hooks/use-account-unit-preferences.ts
|
|
73065
73679
|
/**
|
|
@@ -74424,6 +75038,7 @@ exports.PopoverContent = PopoverContent;
|
|
|
74424
75038
|
exports.PopoverRowAction = PopoverRowAction;
|
|
74425
75039
|
exports.PopoverTrigger = PopoverTrigger;
|
|
74426
75040
|
exports.Power = Power;
|
|
75041
|
+
exports.PowerMeterLine = PowerMeterLine;
|
|
74427
75042
|
exports.PowerOff = PowerOff;
|
|
74428
75043
|
exports.PrimaryChildPicker = PrimaryChildPicker;
|
|
74429
75044
|
exports.PrivacyMaskSettings = PrivacyMaskSettings;
|
|
@@ -74450,6 +75065,8 @@ exports.RecordEntriesPanel = RecordEntriesPanel;
|
|
|
74450
75065
|
exports.RecordedPlaybackProvider = RecordedPlaybackProvider;
|
|
74451
75066
|
exports.RecordingPanel = RecordingPanel;
|
|
74452
75067
|
exports.RefreshCw = RefreshCw;
|
|
75068
|
+
exports.Repeat = Repeat;
|
|
75069
|
+
exports.Repeat1 = Repeat1;
|
|
74453
75070
|
exports.ResponseLog = ResponseLog;
|
|
74454
75071
|
exports.RetrainReviewBadge = RetrainReviewBadge;
|
|
74455
75072
|
exports.RoleDisplayDefaultsFromServer = RoleDisplayDefaultsFromServer;
|
|
@@ -74533,6 +75150,7 @@ exports.ShieldAlert = ShieldAlert;
|
|
|
74533
75150
|
exports.ShieldCheck = ShieldCheck;
|
|
74534
75151
|
exports.ShieldOff = ShieldOff;
|
|
74535
75152
|
exports.Ship = Ship;
|
|
75153
|
+
exports.Shuffle = Shuffle;
|
|
74536
75154
|
exports.Sidebar = Sidebar;
|
|
74537
75155
|
exports.SidebarItem = SidebarItem;
|
|
74538
75156
|
exports.Siren = Siren;
|
|
@@ -75627,6 +76245,8 @@ exports.useLockControlLock = useLockControlLock;
|
|
|
75627
76245
|
exports.useLockControlOpen = useLockControlOpen;
|
|
75628
76246
|
exports.useLockControlUnlock = useLockControlUnlock;
|
|
75629
76247
|
exports.useLockDoorSensor = useLockDoorSensor;
|
|
76248
|
+
exports.useMediaPlayerChannelDown = useMediaPlayerChannelDown;
|
|
76249
|
+
exports.useMediaPlayerChannelUp = useMediaPlayerChannelUp;
|
|
75630
76250
|
exports.useMediaPlayerGetStatus = useMediaPlayerGetStatus;
|
|
75631
76251
|
exports.useMediaPlayerNext = useMediaPlayerNext;
|
|
75632
76252
|
exports.useMediaPlayerPause = useMediaPlayerPause;
|
|
@@ -75640,6 +76260,10 @@ exports.useMediaPlayerSetRepeat = useMediaPlayerSetRepeat;
|
|
|
75640
76260
|
exports.useMediaPlayerSetShuffle = useMediaPlayerSetShuffle;
|
|
75641
76261
|
exports.useMediaPlayerSetVolume = useMediaPlayerSetVolume;
|
|
75642
76262
|
exports.useMediaPlayerStop = useMediaPlayerStop;
|
|
76263
|
+
exports.useMediaPlayerTurnOff = useMediaPlayerTurnOff;
|
|
76264
|
+
exports.useMediaPlayerTurnOn = useMediaPlayerTurnOn;
|
|
76265
|
+
exports.useMediaPlayerVolumeDown = useMediaPlayerVolumeDown;
|
|
76266
|
+
exports.useMediaPlayerVolumeUp = useMediaPlayerVolumeUp;
|
|
75643
76267
|
exports.useMeshNetworkGetStatus = useMeshNetworkGetStatus;
|
|
75644
76268
|
exports.useMeshNetworkJoin = useMeshNetworkJoin;
|
|
75645
76269
|
exports.useMeshNetworkLeave = useMeshNetworkLeave;
|
|
@@ -76126,6 +76750,7 @@ exports.useRecordingOnboardSetSettings = useRecordingOnboardSetSettings;
|
|
|
76126
76750
|
exports.useRecordingSignalGetStatus = useRecordingSignalGetStatus;
|
|
76127
76751
|
exports.useRegisteredHotkeys = useRegisteredHotkeys;
|
|
76128
76752
|
exports.useRemoteComponent = useRemoteComponent;
|
|
76753
|
+
exports.useRemoteGetAssumedStatus = useRemoteGetAssumedStatus;
|
|
76129
76754
|
exports.useRemoteGetConfig = useRemoteGetConfig;
|
|
76130
76755
|
exports.useRemoteLayoutComponentsListComponents = useRemoteLayoutComponentsListComponents;
|
|
76131
76756
|
exports.useRemoteListCommands = useRemoteListCommands;
|