diff --git a/main.py b/main.py index 2e1b0aa..e8377e0 100644 --- a/main.py +++ b/main.py @@ -39,11 +39,15 @@ async def get_settings(self): async def save_rgb_per_game_profiles_enabled(self, enabled: bool): return settings.set_setting('rgbPerGameProfilesEnabled', enabled) - async def save_rgb_settings(self, rgbProfiles): - return settings.set_all_rgb_profiles(rgbProfiles) + async def save_rgb_settings(self, rgbProfiles, currentGameId): + result = settings.set_all_rgb_profiles(rgbProfiles) + if currentGameId: + rgb.sync_rgb_settings(currentGameId) + return result + # sync state in settings.json to actual controller RGB hardware async def sync_rgb_settings(self, currentGameId): - decky_plugin.logger.info(f"sync rgb settings {currentGameId}") + # decky_plugin.logger.info(f"sync rgb settings {currentGameId}") return rgb.sync_rgb_settings(currentGameId) async def remap_button(self, button: str, action: str): diff --git a/py_modules/controller_enums.py b/py_modules/controller_enums.py index 1cf70bf..2407ff6 100644 --- a/py_modules/controller_enums.py +++ b/py_modules/controller_enums.py @@ -43,4 +43,9 @@ class RemapActions(Enum): R_TRIGGER = 0x19 VIEW = 0x23 - MENU = 0x24 \ No newline at end of file + MENU = 0x24 + +class RgbModes(Enum): + SOLID = 0x01 + DYNAMIC = 0x03 + BLINKING = 0x02 \ No newline at end of file diff --git a/py_modules/rgb.py b/py_modules/rgb.py index e1f83e7..5b1be26 100644 --- a/py_modules/rgb.py +++ b/py_modules/rgb.py @@ -10,6 +10,7 @@ def sync_rgb_settings(current_game_id): rgb_profile = s.get('rgb').get(current_game_id) for controller in ['LEFT', 'RIGHT']: rgb_light = rgb_profile.get(controller) + rgb_mode = rgb_light.get('mode') if rgb_light.get('enabled'): rgb_on(current_game_id, controller) @@ -17,6 +18,7 @@ def sync_rgb_settings(current_game_id): rgb_color( current_game_id, controller, + rgb_mode, rgb_light.get('red'), rgb_light.get('blue'), rgb_light.get('green'), @@ -38,10 +40,12 @@ def rgb_off(current_game_id, controller: str): legion_configurator.send_command(rgb_off_command) -def rgb_color(current_game_id, controller: str, red, blue, green, brightness): +def rgb_color(current_game_id, controller: str, mode: str, red, blue, green, brightness): hex_brightness = int(brightness) color = bytes([red, green, blue]) controller_code = controller_enums.Controller[controller].value - rgb = legion_configurator.create_rgb_control_command(controller_code,0x01,color, hex_brightness, 0x01) + rgb_mode_code = controller_enums.RgbModes[mode].value or controller_enums.RgbModes['SOLID'].value + + rgb = legion_configurator.create_rgb_control_command(controller_code, rgb_mode_code, color, hex_brightness, 0x01) # decky_plugin.logger.info(list(rgb)) legion_configurator.send_command(rgb) \ No newline at end of file diff --git a/src/backend/constants.tsx b/src/backend/constants.tsx index c0a2d98..00992ad 100644 --- a/src/backend/constants.tsx +++ b/src/backend/constants.tsx @@ -40,3 +40,9 @@ export enum RemapActions { VIEW = 'VIEW', MENU = 'MENU' } + +export enum RgbModes { + SOLID = 'SOLID', + DYNAMIC = 'DYNAMIC', + BLINKING = 'BLINKING' +} diff --git a/src/components/ControllerLightingPanel.tsx b/src/components/ControllerLightingPanel.tsx index d196a8f..0277d28 100644 --- a/src/components/ControllerLightingPanel.tsx +++ b/src/components/ControllerLightingPanel.tsx @@ -10,8 +10,11 @@ import { useState } from 'react'; import { useRgb, usePerGameRgbProfilesEnabled, - useRgbProfileDisplayName + useRgbProfileDisplayName, + useRgbMode } from '../hooks/rgb'; +import RgbModeDropdown from './RgbModeDropdown'; +import { RgbModes } from '../backend/constants'; const DEFAULT_STATE = { isTouchpad: true }; @@ -19,6 +22,9 @@ const DEFAULT_STATE = { const ControllerLightingPanel: VFC<{ serverAPI: ServerAPI }> = ({ serverAPI }) => { + const [leftMode] = useRgbMode('LEFT'); + const [rightMode] = useRgbMode('RIGHT'); + const [perGameProfilesEnabled, setPerGameProfilesEnabled] = usePerGameRgbProfilesEnabled(); const displayName = useRgbProfileDisplayName(); @@ -89,6 +95,7 @@ const ControllerLightingPanel: VFC<{ serverAPI: ServerAPI }> = ({ )} {showRightOptions && isRightRgbOn && ( <> + = ({ validValues="range" onChange={(value) => setRightLedBrightness(value)} > - <> - { - setRightColor('red', value); - }} - /> - { - setRightColor('green', value); - }} - /> - { - setRightColor('blue', value); - }} - /> -
- + {rightMode !== RgbModes.DYNAMIC && ( + <> + { + setRightColor('red', value); + }} + /> + { + setRightColor('green', value); + }} + /> + { + setRightColor('blue', value); + }} + /> +
+ + )} )} @@ -162,6 +171,7 @@ const ControllerLightingPanel: VFC<{ serverAPI: ServerAPI }> = ({ )} {showLeftOptions && isLeftRgbOn && ( <> + = ({ validValues="range" onChange={(value) => setLeftLedBrightness(value)} > - <> - { - setLeftColor('red', value); - }} - /> - { - setLeftColor('green', value); - }} - /> - { - setLeftColor('blue', value); - }} - /> -
- + {leftMode !== RgbModes.DYNAMIC && ( + <> + { + setLeftColor('red', value); + }} + /> + { + setLeftColor('green', value); + }} + /> + { + setLeftColor('blue', value); + }} + /> +
+ + )} )} diff --git a/src/components/RgbModeDropdown.tsx b/src/components/RgbModeDropdown.tsx new file mode 100644 index 0000000..7598c3f --- /dev/null +++ b/src/components/RgbModeDropdown.tsx @@ -0,0 +1,46 @@ +import { FC } from 'react'; +import { DropdownItem } from 'decky-frontend-lib'; +import { ControllerType, RgbModes } from '../backend/constants'; +import { useRgbMode } from '../hooks/rgb'; + +type PropType = { + controller: ControllerType; +}; + +const RgbModeDropdown: FC = ({ controller }) => { + const [mode, setMode] = useRgbMode(controller); + + const dropdownOptions = Object.values(RgbModes).map((action) => { + return { + data: action, + label: `${action}`, + value: action + }; + }); + + return ( + <> + { + return { + data: o.data, + label: o.label, + value: o.value + }; + })} + selectedOption={ + dropdownOptions.find((o) => { + return o.data === mode; + })?.data + } + onChange={(value: any) => { + setMode(value.data); + }} + /> + + ); +}; + +export default RgbModeDropdown; diff --git a/src/hooks/rgb.tsx b/src/hooks/rgb.tsx index bbd0ee2..36e9f51 100644 --- a/src/hooks/rgb.tsx +++ b/src/hooks/rgb.tsx @@ -1,11 +1,12 @@ import { useDispatch, useSelector } from 'react-redux'; import { useCallback } from 'react'; -import { ControllerType } from '../backend/constants'; +import { ControllerType, RgbModes } from '../backend/constants'; import { rgbSlice, selectRgbInfo, selectRgbProfileDisplayName, - selectPerGameProfilesEnabled + selectPerGameProfilesEnabled, + selectRgbMode } from '../redux-modules/rgbSlice'; export enum Colors { @@ -14,6 +15,20 @@ export enum Colors { BLUE = 'blue' } +export const useRgbMode = (controller: ControllerType) => { + const mode = useSelector(selectRgbMode(controller)); + const dispatch = useDispatch(); + + const setMode = useCallback( + (mode: RgbModes) => { + return dispatch(rgbSlice.actions.setRgbMode({ controller, mode })); + }, + [controller] + ); + + return [mode, setMode] as any; +}; + export const usePerGameRgbProfilesEnabled = () => { const isEnabled = useSelector(selectPerGameProfilesEnabled); const dispatch = useDispatch(); diff --git a/src/redux-modules/rgbSlice.tsx b/src/redux-modules/rgbSlice.tsx index 47fab80..8131a0e 100644 --- a/src/redux-modules/rgbSlice.tsx +++ b/src/redux-modules/rgbSlice.tsx @@ -4,11 +4,12 @@ import { get, merge } from 'lodash'; import type { RootState } from './store'; import { setCurrentGameId, setInitialState } from './extraActions'; import { extractCurrentGameId, getServerApi } from '../backend/utils'; -import { ControllerType } from '../backend/constants'; +import { ControllerType, RgbModes } from '../backend/constants'; import { Router } from 'decky-frontend-lib'; -const DEFAULT_RGB_LIGHT_VALUES = { +const DEFAULT_RGB_LIGHT_VALUES: RgbLight = { enabled: false, + mode: RgbModes.SOLID, red: 255, green: 255, blue: 255, @@ -23,6 +24,7 @@ enum Colors { type RgbLight = { enabled: boolean; + mode: RgbModes; red: number; green: number; blue: number; @@ -77,6 +79,18 @@ export const rgbSlice = createSlice({ bootstrapRgbProfile(state, extractCurrentGameId()); } }, + setRgbMode: ( + state, + action: PayloadAction<{ controller: string; mode: RgbModes }> + ) => { + const { controller, mode } = action.payload; + if (state.perGameProfilesEnabled) { + const currentGameId = extractCurrentGameId(); + state.rgbProfiles[currentGameId][controller]['mode'] = mode; + } else { + state.rgbProfiles['default'][controller]['mode'] = mode; + } + }, updateRgbProfiles: (state, action: PayloadAction) => { merge(state.rgbProfiles, action.payload); }, @@ -165,6 +179,19 @@ export const selectRgbInfo = return rgbInfo; }; +export const selectRgbMode = + (controller: ControllerType) => (state: RootState) => { + const currentGameId = extractCurrentGameId(); + let rgbMode; + if (state.rgb.perGameProfilesEnabled) { + rgbMode = state.rgb.rgbProfiles[currentGameId][controller].mode; + } else { + rgbMode = state.rgb.rgbProfiles['default'][controller].mode; + } + + return rgbMode; + }; + export const selectPerGameProfilesEnabled = (state: RootState) => { return state.rgb.perGameProfilesEnabled; }; @@ -185,7 +212,8 @@ const mutatingActionTypes = [ rgbSlice.actions.updateRgbProfiles.type, rgbSlice.actions.setColor.type, rgbSlice.actions.setEnabled.type, - rgbSlice.actions.setPerGameProfilesEnabled, + rgbSlice.actions.setPerGameProfilesEnabled.type, + rgbSlice.actions.setRgbMode.type, rgbSlice.actions.setBrightness.type ]; @@ -199,25 +227,16 @@ export const saveRgbSettingsMiddleware = if (mutatingActionTypes.includes(type)) { // get latest state from store const { - rgb: { rgbProfiles } + rgb: { rgbProfiles, perGameProfilesEnabled } } = store.getState(); + const currentGameId = perGameProfilesEnabled + ? extractCurrentGameId() + : 'default'; - serverApi - ?.callPluginMethod('save_rgb_settings', { rgbProfiles }) - .then((res) => { - const { - rgb: { perGameProfilesEnabled } - } = store.getState(); - - const currentGameId = perGameProfilesEnabled - ? extractCurrentGameId() - : 'default'; - - if (res.success) { - // since RGB settings changed, update state of RBG lights - serverApi.callPluginMethod('sync_rgb_settings', { currentGameId }); - } - }); + serverApi?.callPluginMethod('save_rgb_settings', { + rgbProfiles, + currentGameId + }); } if (type === setInitialState.type || type === setCurrentGameId.type) { // tell backend to sync LEDs to current FE state