diff --git a/proto/overlay-sidecar.proto b/proto/overlay-sidecar.proto index baf47e52..3b3e98e8 100644 --- a/proto/overlay-sidecar.proto +++ b/proto/overlay-sidecar.proto @@ -58,6 +58,7 @@ message OyasumiSidecarState { bool sleep_preparation_available = 9; bool sleep_preparation_timed_out = 10; bool system_mic_muted = 11; + OyasumiSidecarCCTState cct_state = 12; } // No longer required, but reserved for future settings @@ -162,6 +163,15 @@ message OyasumiSidecarBrightnessState { double hardware_max_brightness = 13; } +message OyasumiSidecarCCTState { + bool enabled = 1; + uint32 value = 2; + uint32 min = 3; + uint32 max = 4; + bool transitioning = 5; + uint32 transition_target = 6; +} + enum VrcStatus { VRC_STATUS_Offline = 0; VRC_STATUS_Busy = 1; diff --git a/src-grpc-web-client/overlay-sidecar_pb.ts b/src-grpc-web-client/overlay-sidecar_pb.ts index 5cd76dae..8ff26cb6 100644 --- a/src-grpc-web-client/overlay-sidecar_pb.ts +++ b/src-grpc-web-client/overlay-sidecar_pb.ts @@ -128,6 +128,10 @@ export interface OyasumiSidecarState { * @generated from protobuf field: bool system_mic_muted = 11; */ systemMicMuted: boolean; + /** + * @generated from protobuf field: OyasumiOverlaySidecar.OyasumiSidecarCCTState cct_state = 12; + */ + cctState?: OyasumiSidecarCCTState; } /** * No longer required, but reserved for future settings @@ -434,6 +438,35 @@ export interface OyasumiSidecarBrightnessState { */ hardwareMaxBrightness: number; } +/** + * @generated from protobuf message OyasumiOverlaySidecar.OyasumiSidecarCCTState + */ +export interface OyasumiSidecarCCTState { + /** + * @generated from protobuf field: bool enabled = 1; + */ + enabled: boolean; + /** + * @generated from protobuf field: uint32 value = 2; + */ + value: number; + /** + * @generated from protobuf field: uint32 min = 3; + */ + min: number; + /** + * @generated from protobuf field: uint32 max = 4; + */ + max: number; + /** + * @generated from protobuf field: bool transitioning = 5; + */ + transitioning: boolean; + /** + * @generated from protobuf field: uint32 transition_target = 6; + */ + transitionTarget: number; +} /** * @generated from protobuf enum OyasumiOverlaySidecar.OyasumiSidecarAutomationsState_AutoAcceptInviteRequests_Mode */ @@ -962,6 +995,7 @@ class OyasumiSidecarState$Type extends MessageType { { no: 9, name: 'sleep_preparation_available', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ }, { no: 10, name: 'sleep_preparation_timed_out', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ }, { no: 11, name: 'system_mic_muted', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ }, + { no: 12, name: 'cct_state', kind: 'message', T: () => OyasumiSidecarCCTState }, ]); } create(value?: PartialMessage): OyasumiSidecarState { @@ -1042,6 +1076,14 @@ class OyasumiSidecarState$Type extends MessageType { case /* bool system_mic_muted */ 11: message.systemMicMuted = reader.bool(); break; + case /* OyasumiOverlaySidecar.OyasumiSidecarCCTState cct_state */ 12: + message.cctState = OyasumiSidecarCCTState.internalBinaryRead( + reader, + reader.uint32(), + options, + message.cctState + ); + break; default: let u = options.readUnknownField; if (u === 'throw') @@ -1112,6 +1154,13 @@ class OyasumiSidecarState$Type extends MessageType { /* bool system_mic_muted = 11; */ if (message.systemMicMuted !== false) writer.tag(11, WireType.Varint).bool(message.systemMicMuted); + /* OyasumiOverlaySidecar.OyasumiSidecarCCTState cct_state = 12; */ + if (message.cctState) + OyasumiSidecarCCTState.internalBinaryWrite( + message.cctState, + writer.tag(12, WireType.LengthDelimited).fork(), + options + ).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; @@ -2414,6 +2463,106 @@ class OyasumiSidecarBrightnessState$Type extends MessageType { + constructor() { + super('OyasumiOverlaySidecar.OyasumiSidecarCCTState', [ + { no: 1, name: 'enabled', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ }, + { no: 2, name: 'value', kind: 'scalar', T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: 'min', kind: 'scalar', T: 13 /*ScalarType.UINT32*/ }, + { no: 4, name: 'max', kind: 'scalar', T: 13 /*ScalarType.UINT32*/ }, + { no: 5, name: 'transitioning', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ }, + { no: 6, name: 'transition_target', kind: 'scalar', T: 13 /*ScalarType.UINT32*/ }, + ]); + } + create(value?: PartialMessage): OyasumiSidecarCCTState { + const message = { + enabled: false, + value: 0, + min: 0, + max: 0, + transitioning: false, + transitionTarget: 0, + }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead( + reader: IBinaryReader, + length: number, + options: BinaryReadOptions, + target?: OyasumiSidecarCCTState + ): OyasumiSidecarCCTState { + let message = target ?? this.create(), + end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bool enabled */ 1: + message.enabled = reader.bool(); + break; + case /* uint32 value */ 2: + message.value = reader.uint32(); + break; + case /* uint32 min */ 3: + message.min = reader.uint32(); + break; + case /* uint32 max */ 4: + message.max = reader.uint32(); + break; + case /* bool transitioning */ 5: + message.transitioning = reader.bool(); + break; + case /* uint32 transition_target */ 6: + message.transitionTarget = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === 'throw') + throw new globalThis.Error( + `Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}` + ); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)( + this.typeName, + message, + fieldNo, + wireType, + d + ); + } + } + return message; + } + internalBinaryWrite( + message: OyasumiSidecarCCTState, + writer: IBinaryWriter, + options: BinaryWriteOptions + ): IBinaryWriter { + /* bool enabled = 1; */ + if (message.enabled !== false) writer.tag(1, WireType.Varint).bool(message.enabled); + /* uint32 value = 2; */ + if (message.value !== 0) writer.tag(2, WireType.Varint).uint32(message.value); + /* uint32 min = 3; */ + if (message.min !== 0) writer.tag(3, WireType.Varint).uint32(message.min); + /* uint32 max = 4; */ + if (message.max !== 0) writer.tag(4, WireType.Varint).uint32(message.max); + /* bool transitioning = 5; */ + if (message.transitioning !== false) writer.tag(5, WireType.Varint).bool(message.transitioning); + /* uint32 transition_target = 6; */ + if (message.transitionTarget !== 0) + writer.tag(6, WireType.Varint).uint32(message.transitionTarget); + let u = options.writeUnknownFields; + if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message OyasumiOverlaySidecar.OyasumiSidecarCCTState + */ +export const OyasumiSidecarCCTState = new OyasumiSidecarCCTState$Type(); /** * @generated ServiceType for protobuf service OyasumiOverlaySidecar.OyasumiOverlaySidecar */ diff --git a/src-overlay-sidecar/Overlays/Helpers/OverlayPointer.cs b/src-overlay-sidecar/Overlays/Helpers/OverlayPointer.cs index 9308e4a0..96e06708 100644 --- a/src-overlay-sidecar/Overlays/Helpers/OverlayPointer.cs +++ b/src-overlay-sidecar/Overlays/Helpers/OverlayPointer.cs @@ -36,7 +36,7 @@ public OverlayPointer() OpenVR.Overlay.SetOverlaySortOrder(_leftPointer.OverlayHandle, 150); OpenVR.Overlay.SetOverlaySortOrder(_rightPointer.OverlayHandle, 150); // Load pointer image into overlays - var pointerImage = Utils.ConvertPngToRgba(Utils.LoadEmbeddedFile("overlay-sidecar.Resources.pointer.png")); + var pointerImage = Utils.ConvertPngToRgba(Utils.LoadEmbeddedFile("oyasumivr-overlay-sidecar.Resources.pointer.png")); var intPtr = Marshal.AllocHGlobal(pointerImage.Item1.Length); Marshal.Copy(pointerImage.Item1, 0, intPtr, pointerImage.Item1.Length); OpenVR.Overlay.SetOverlayRaw(_rightPointer.OverlayHandle, intPtr, (uint)pointerImage.Item2, diff --git a/src-overlay-sidecar/Overlays/MicMuteIndicatorOverlay.cs b/src-overlay-sidecar/Overlays/MicMuteIndicatorOverlay.cs index 2ba66e8f..a3ae7a1c 100644 --- a/src-overlay-sidecar/Overlays/MicMuteIndicatorOverlay.cs +++ b/src-overlay-sidecar/Overlays/MicMuteIndicatorOverlay.cs @@ -29,9 +29,9 @@ public MicMuteIndicatorOverlay() { // Load image resources _muteImage = - Utils.ConvertPngToRgba(Utils.LoadEmbeddedFile("oyasumi-overlay-sidecar.Resources.mic_mute.png")); + Utils.ConvertPngToRgba(Utils.LoadEmbeddedFile("oyasumivr-overlay-sidecar.Resources.mic_mute.png")); _unmuteImage = - Utils.ConvertPngToRgba(Utils.LoadEmbeddedFile("oyasumi-overlay-sidecar.Resources.mic_unmute.png")); + Utils.ConvertPngToRgba(Utils.LoadEmbeddedFile("oyasumivr-overlay-sidecar.Resources.mic_unmute.png")); _textureWriter = new TextureWriter(512); // Create the overlay OpenVR.Overlay.CreateOverlay("co.raphii.oyasumivr:MicMuteIndicatorOverlay", "OyasumiVR Mic Mute Indicator Overlay", diff --git a/src-overlay-sidecar/src-overlay-sidecar.sln b/src-overlay-sidecar/src-overlay-sidecar.sln new file mode 100644 index 00000000..11481d86 --- /dev/null +++ b/src-overlay-sidecar/src-overlay-sidecar.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "oyasumivr-overlay-sidecar", "oyasumivr-overlay-sidecar.csproj", "{240CFAD1-7680-4BA7-8F6B-A1D23ABBBB91}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {240CFAD1-7680-4BA7-8F6B-A1D23ABBBB91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {240CFAD1-7680-4BA7-8F6B-A1D23ABBBB91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {240CFAD1-7680-4BA7-8F6B-A1D23ABBBB91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {240CFAD1-7680-4BA7-8F6B-A1D23ABBBB91}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C577E4CD-0E1C-477D-9396-41D59EBF9B86} + EndGlobalSection +EndGlobal diff --git a/src-overlay-ui/package-lock.json b/src-overlay-ui/package-lock.json index ca3857e6..6efac715 100644 --- a/src-overlay-ui/package-lock.json +++ b/src-overlay-ui/package-lock.json @@ -13,7 +13,8 @@ "just-throttle": "^4.2.0", "lodash-es": "^4.17.21", "material-icons": "^1.13.8", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "tailwindcss-multi": "^0.4.6" }, "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", @@ -515,6 +516,14 @@ "@types/lodash": "*" } }, + "node_modules/@types/node": { + "version": "20.15.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.15.0.tgz", + "integrity": "sha512-eQf4OkH6gA9v1W0iEpht/neozCsZKMTK+C4cU6/fv7wtJCCL8LEQ4hie2Ln8ZP/0YYM2xGj7//f8xyqItkJ6QA==", + "dependencies": { + "undici-types": "~6.13.0" + } + }, "node_modules/@types/pug": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", @@ -3485,6 +3494,14 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss-multi": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/tailwindcss-multi/-/tailwindcss-multi-0.4.6.tgz", + "integrity": "sha512-Bn9yLrMkeYFrJjRYuuTfqT9ibm6U2qnTwlIKYchWyGX3qgL+1+NN4JgiHJG1qrR4QQeU28eCl8sMSBobdzijvQ==", + "dependencies": { + "@types/node": "^20.4.1" + } + }, "node_modules/tailwindcss/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3685,6 +3702,11 @@ "node": ">=14.0" } }, + "node_modules/undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" + }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -4290,6 +4312,14 @@ "@types/lodash": "*" } }, + "@types/node": { + "version": "20.15.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.15.0.tgz", + "integrity": "sha512-eQf4OkH6gA9v1W0iEpht/neozCsZKMTK+C4cU6/fv7wtJCCL8LEQ4hie2Ln8ZP/0YYM2xGj7//f8xyqItkJ6QA==", + "requires": { + "undici-types": "~6.13.0" + } + }, "@types/pug": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz", @@ -6221,6 +6251,14 @@ } } }, + "tailwindcss-multi": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/tailwindcss-multi/-/tailwindcss-multi-0.4.6.tgz", + "integrity": "sha512-Bn9yLrMkeYFrJjRYuuTfqT9ibm6U2qnTwlIKYchWyGX3qgL+1+NN4JgiHJG1qrR4QQeU28eCl8sMSBobdzijvQ==", + "requires": { + "@types/node": "^20.4.1" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6328,6 +6366,11 @@ "busboy": "^1.6.0" } }, + "undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" + }, "update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", diff --git a/src-overlay-ui/package.json b/src-overlay-ui/package.json index 89814f56..07b30494 100644 --- a/src-overlay-ui/package.json +++ b/src-overlay-ui/package.json @@ -42,6 +42,7 @@ "just-throttle": "^4.2.0", "lodash-es": "^4.17.21", "material-icons": "^1.13.8", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "tailwindcss-multi": "^0.4.6" } -} \ No newline at end of file +} diff --git a/src-overlay-ui/splash/index.html b/src-overlay-ui/splash/index.html new file mode 100644 index 00000000..5c42dedf --- /dev/null +++ b/src-overlay-ui/splash/index.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + +
+ +
+ + diff --git a/src-overlay-ui/src/lib/components/BrightnessSlider.svelte b/src-overlay-ui/src/lib/components/BrightnessSlider.svelte index 479094c5..04020a0d 100644 --- a/src-overlay-ui/src/lib/components/BrightnessSlider.svelte +++ b/src-overlay-ui/src/lib/components/BrightnessSlider.svelte @@ -130,10 +130,6 @@ &-title-row { @apply flex flex-row items-center mb-4; - .material-icons { - @apply text-2xl text-white text-center inline-block; - flex-shrink: 0; - } span { @apply text-2xl text-white text-center inline-block; @@ -208,9 +204,7 @@
- {label} -
diff --git a/src-overlay-ui/src/lib/components/BrightnessSliders.svelte b/src-overlay-ui/src/lib/components/BrightnessSliders.svelte index 9f237d10..32079992 100644 --- a/src-overlay-ui/src/lib/components/BrightnessSliders.svelte +++ b/src-overlay-ui/src/lib/components/BrightnessSliders.svelte @@ -1,71 +1,83 @@ +
+ {#if !!brightnessState} + {#if !brightnessState?.advancedMode} +
+ ipc.setBrightness('SIMPLE', value), 16, { + leading: true, + trailing: true + })} + /> +
+ {:else} +
+ ipc.setBrightness('SOFTWARE', value), 16, { + leading: true, + trailing: true + })} + /> + ipc.setBrightness('HARDWARE', value), 16, { + leading: true, + trailing: true + })} + /> +
+ {/if} + {/if} +
+ - -
- {#if !!brightnessState} - {#if !brightnessState?.advancedMode} -
- ipc.setBrightness('SIMPLE', value), 16, {leading: true, trailing: true})} - > -
- {:else} -
- ipc.setBrightness('SOFTWARE', value), 16, {leading: true, trailing: true})} - > - ipc.setBrightness('HARDWARE', value), 16, {leading: true, trailing: true})} - > -
- {/if} - {/if} -
diff --git a/src-overlay-ui/src/lib/components/ColorTempSlider.svelte b/src-overlay-ui/src/lib/components/ColorTempSlider.svelte new file mode 100644 index 00000000..e959f386 --- /dev/null +++ b/src-overlay-ui/src/lib/components/ColorTempSlider.svelte @@ -0,0 +1,232 @@ + + +
+
+
+ {#if !dragging} + {label} + {:else} + {renderValue} + {/if} +
+
+
+
+
+
+
+
+ + diff --git a/src-overlay-ui/src/lib/models/OyasumiState.ts b/src-overlay-ui/src/lib/models/OyasumiState.ts index 52cbd4fe..b921c9d5 100644 --- a/src-overlay-ui/src/lib/models/OyasumiState.ts +++ b/src-overlay-ui/src/lib/models/OyasumiState.ts @@ -56,6 +56,14 @@ export const DEFAULT_OYASUMI_STATE: OyasumiSidecarState = { hardwareMinBrightness: 20, hardwareMaxBrightness: 160 }, + cctState: { + enabled: true, + value: 6600, + min: 1000, + max: 10000, + transitioning: false, + transitionTarget: 6600 + }, sleepPreparationAvailable: false, sleepPreparationTimedOut: false, systemMicMuted: false diff --git a/src-overlay-ui/src/lib/services/ipc.service.ts b/src-overlay-ui/src/lib/services/ipc.service.ts index 457a2340..e2f30636 100644 --- a/src-overlay-ui/src/lib/services/ipc.service.ts +++ b/src-overlay-ui/src/lib/services/ipc.service.ts @@ -168,6 +168,15 @@ class IPCService { }); } + public async setColorTemperature(value: number): Promise { + this.state.update((state) => { + state = cloneDeep(state); + state.cctState!.value = value; + window.OyasumiIPCOut.sendEventDouble('setColorTemperature', value); + return state; + }); + } + public async prepareForSleep() { await window.OyasumiIPCOut.sendEventVoid('prepareForSleep'); } diff --git a/src-overlay-ui/src/routes/dashboard/Overview.svelte b/src-overlay-ui/src/routes/dashboard/Overview.svelte index 8cec6a0e..073138e8 100644 --- a/src-overlay-ui/src/routes/dashboard/Overview.svelte +++ b/src-overlay-ui/src/routes/dashboard/Overview.svelte @@ -1,254 +1,299 @@ -
- -
- Oyasumi Logo -
-
- -
- - -
- nights_stay -
- {$t('t.overlay.dashboard.overview.sleepMode')} - {$state.sleepMode - ? $t('t.overlay.dashboard.overview.active') - : $t('t.overlay.dashboard.overview.inactive')} -
-
-
-
-
- -
- { if (sleepPreparationEnabled) ipc.prepareForSleep() }} - tooltip={$t('t.overlay.dashboard.overview.tooltip.prepareForSleep')} - > - -
- bedtime -
-
-
-
- -
+ +
+ Oyasumi Logo +
+
+ +
+ + +
+ nights_stay +
+ {$t('t.overlay.dashboard.overview.sleepMode')} + {$state.sleepMode + ? $t('t.overlay.dashboard.overview.active') + : $t('t.overlay.dashboard.overview.inactive')} +
+
+
+
+
+ +
+ { + if (sleepPreparationEnabled) ipc.prepareForSleep(); + }} + tooltip={$t('t.overlay.dashboard.overview.tooltip.prepareForSleep')} + > + +
+ bedtime +
+
+
+
+ +
- { + > + { dispatch('nav', { mode: 'AUTOMATIONS' }); }} - tooltip={$t('t.overlay.dashboard.overview.tooltip.automations')} - > - -
- settings_suggest -
-
-
-
- -
+ +
+ settings_suggest +
+
+ +
+ +
- { + > + { dispatch('nav', { mode: 'DEVICE_CONTROL' }); }} - tooltip={$t('t.overlay.dashboard.overview.tooltip.deviceControl')} - > - -
- -
-
-
-
- -
+ +
+ +
+
+ +
+ +
- { + > + { if (!shutdownSequenceDisabled) dispatch('openShutdownSequence'); }} - tooltip={$t('t.overlay.dashboard.overview.tooltip.shutdown')} - > - -
- settings_power -
-
-
-
- -
- -
+ +
+ settings_power +
+
+ +
+
+ +
- -
- {#if $vrcLoggedIn} -
-
+ {#if $vrcLoggedIn} +
+
- {$state.vrcUsername} -
- {/if} -
- {timeHours}:{timeMinutes} - access_time -
-
- -
- -
+ {$state.vrcUsername} +
+ {/if} +
+ {timeHours}:{timeMinutes} + access_time +
+
+ + {#if cctState.enabled} + sliderMode.set($sliderModeButtonMode)} + > + + {#if $sliderModeButtonMode === 'COLOR_TEMP'} +
+ thermostat +
+ {:else if $sliderModeButtonMode === 'BRIGHTNESS'} +
+ wb_sunny +
+ {/if} +
+
+ {/if} + {/if} +
+ +
- -
+ > + {#if $sliderMode === 'BRIGHTNESS'} +
+ +
+ {:else if $sliderMode === 'COLOR_TEMP'} +
+ {#if !!cctState} + ipc.setColorTemperature(value), 16, { + leading: true, + trailing: true + })} + /> + {/if} +
+ {/if} +
diff --git a/src-overlay-ui/tailwind.config.js b/src-overlay-ui/tailwind.config.js index 7aa38ee2..34cb3b6f 100644 --- a/src-overlay-ui/tailwind.config.js +++ b/src-overlay-ui/tailwind.config.js @@ -1,10 +1,9 @@ /** @type {import("tailwindcss").Config} */ export default { - mode: "jit", - purge: ["./src/**/*.svelte"], - theme: { - extend: {} - }, - plugins: [] + mode: 'jit', + purge: ['./src/**/*.svelte'], + theme: { + extend: {} + }, + plugins: [require('tailwindcss-multi')] }; - diff --git a/src-ui/app/components/cct-control-modal/cct-control-modal.component.ts b/src-ui/app/components/cct-control-modal/cct-control-modal.component.ts index ecc60889..b9f97b79 100644 --- a/src-ui/app/components/cct-control-modal/cct-control-modal.component.ts +++ b/src-ui/app/components/cct-control-modal/cct-control-modal.component.ts @@ -15,8 +15,6 @@ import { CCTControlService } from '../../services/cct-control/cct-control.servic animations: [fadeUp(), vshrink(), hshrink()], }) export class CCTControlModalComponent extends BaseModalComponent implements OnInit { - cctBounds = [1000, 10000]; - protected readonly setCCT = new Subject(); constructor( diff --git a/src-ui/app/services/overlay/overlay-state-sync.service.ts b/src-ui/app/services/overlay/overlay-state-sync.service.ts index 7bcc0bdd..8b00b5be 100644 --- a/src-ui/app/services/overlay/overlay-state-sync.service.ts +++ b/src-ui/app/services/overlay/overlay-state-sync.service.ts @@ -40,6 +40,7 @@ import { HardwareBrightnessControlService } from '../brightness-control/hardware import { SoftwareBrightnessControlService } from '../brightness-control/software-brightness-control.service'; import { SleepPreparationService } from '../sleep-preparation.service'; import { SystemMicMuteAutomationService } from '../system-mic-mute-automation.service'; +import { CCTControlService } from '../cct-control/cct-control.service'; @Injectable({ providedIn: 'root', @@ -113,6 +114,14 @@ export class OverlayStateSyncService { hardwareMinBrightness: 20, hardwareMaxBrightness: 160, }, + cctState: { + enabled: APP_SETTINGS_DEFAULT.cctControlEnabled, + value: 6600, + min: 1000, + max: 10000, + transitioning: false, + transitionTarget: 6600, + }, sleepPreparationAvailable: false, sleepPreparationTimedOut: false, systemMicMuted: false, @@ -123,6 +132,7 @@ export class OverlayStateSyncService { private vrchatService: VRChatService, private ipcService: IPCService, private automationConfig: AutomationConfigService, + private cctService: CCTControlService, private appSettings: AppSettingsService, private shutdownAutomationsService: ShutdownAutomationsService, private openvr: OpenVRService, @@ -143,6 +153,7 @@ export class OverlayStateSyncService { this.updateState_WhenOVRDevicesChange(); this.updateState_WhenAppSettingsChange(); this.updateState_WhenBrightnessStateChanges(); + this.updateState_WhenCCTStateChanges(); this.updateState_WhenSleepPreparationStateChanges(); this.updateState_WhenSystemMicMuteStateChanges(); } @@ -393,6 +404,30 @@ export class OverlayStateSyncService { }); } + private updateState_WhenCCTStateChanges() { + this.appSettings.settings + .pipe( + map((settings) => settings.cctControlEnabled), + distinctUntilChanged() + ) + .subscribe((enabled) => { + const state = structuredClone(this.state.value); + state.cctState!.enabled = enabled; + this.state.next(state); + }); + this.cctService.cctStream.pipe(distinctUntilChanged()).subscribe((value) => { + const state = structuredClone(this.state.value); + state.cctState!.value = value; + this.state.next(state); + }); + this.cctService.activeTransition.pipe(distinctUntilChanged()).subscribe((transition) => { + const state = structuredClone(this.state.value); + state.cctState!.transitioning = !!transition; + if (transition) state.cctState!.transitionTarget = transition.targetCCT; + this.state.next(state); + }); + } + private updateState_WhenSleepPreparationStateChanges() { this.sleepPreparation.sleepPreparationAvailable.subscribe((available) => { const state = structuredClone(this.state.value); diff --git a/src-ui/app/views/dashboard-view/views/brightness-automations-view/tabs/new-brightness-automations-tab/brightness-automation-details/brightness-automation-details.component.ts b/src-ui/app/views/dashboard-view/views/brightness-automations-view/tabs/new-brightness-automations-tab/brightness-automation-details/brightness-automation-details.component.ts index a4dae2ce..827c7c8a 100644 --- a/src-ui/app/views/dashboard-view/views/brightness-automations-view/tabs/new-brightness-automations-tab/brightness-automation-details/brightness-automation-details.component.ts +++ b/src-ui/app/views/dashboard-view/views/brightness-automations-view/tabs/new-brightness-automations-tab/brightness-automation-details/brightness-automation-details.component.ts @@ -100,30 +100,33 @@ export class BrightnessAutomationDetailsComponent implements OnInit { } protected async updateBrightness(type: BrightnessType, value: number | 'CURRENT') { + const copyCurrent = value === 'CURRENT'; const pConfig: Partial = {}; switch (type) { case 'SIMPLE': { - if (value === 'CURRENT') value = this.simpleBrightnessControl.brightness; - pConfig.brightness = Math.round(value); + if (copyCurrent) value = this.simpleBrightnessControl.brightness; + pConfig.brightness = Math.round(value as number); break; } case 'SOFTWARE': { - if (value === 'CURRENT') value = this.softwareBrightnessControl.brightness; - pConfig.softwareBrightness = Math.round(value); + if (copyCurrent) value = this.softwareBrightnessControl.brightness; + pConfig.softwareBrightness = Math.round(value as number); break; } case 'HARDWARE': { - if (value === 'CURRENT') value = this.hardwareBrightnessControl.brightness; - pConfig.hardwareBrightness = Math.round(value); + if (copyCurrent) value = this.hardwareBrightnessControl.brightness; + pConfig.hardwareBrightness = Math.round(value as number); break; } } await this.updateConfig(pConfig); - this.vshakeElements.push('BRIGHTNESS_' + type); - setTimeout(() => { - const index = this.vshakeElements.indexOf('BRIGHTNESS_' + type); - if (index >= 0) this.vshakeElements.splice(index, 1); - }, 300); + if (copyCurrent) { + this.vshakeElements.push('BRIGHTNESS_' + type); + setTimeout(() => { + const index = this.vshakeElements.indexOf('BRIGHTNESS_' + type); + if (index >= 0) this.vshakeElements.splice(index, 1); + }, 300); + } } protected async toggleChangeBrightness() { diff --git a/src-ui/assets/i18n/en.json b/src-ui/assets/i18n/en.json index c2ddad79..0c1d8d3e 100644 --- a/src-ui/assets/i18n/en.json +++ b/src-ui/assets/i18n/en.json @@ -1293,6 +1293,7 @@ "simple": "Brightness", "software": "Software Brightness" }, + "colorTemp": "Color Temperature", "dashboard": { "automations": { "autoAcceptInviteRequests": { @@ -1340,7 +1341,11 @@ "automations": "Automations", "deviceControl": "Device Control", "prepareForSleep": "Prepare for sleep", - "shutdown": "Shutdown Sequence" + "shutdown": "Shutdown Sequence", + "sliderMode": { + "BRIGHTNESS": "Brightness Control", + "COLOR_TEMP": "Color Temperature Control" + } } }, "shutdownSequence": { @@ -2505,4 +2510,4 @@ }, "title": "VRChat Microphone Mute Automations" } -} \ No newline at end of file +}