From 260f40fef3d698b2c99104f51f7c699ab6650411 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 5 Aug 2023 22:40:00 +0000 Subject: [PATCH] dynamic actions --- src/Components/ColorPicker/index.js | 6 +- src/Components/Slider/index.js | 2 + .../AddSceneAction/LayerSelection/index.js | 3 +- .../Device/modals/AddSceneAction/index.js | 28 ++- .../Device/modals/EditActions/Lights/index.js | 87 ++++--- .../Device/modals/EditActions/index.js | 160 ++++++++---- src/Screens/Device/scene.js | 235 +++++++++++------- src/utils.js | 108 +++++--- 8 files changed, 411 insertions(+), 218 deletions(-) diff --git a/src/Components/ColorPicker/index.js b/src/Components/ColorPicker/index.js index 23d1a2c..e895ab1 100644 --- a/src/Components/ColorPicker/index.js +++ b/src/Components/ColorPicker/index.js @@ -254,6 +254,8 @@ export function MyColorPickerV2({ isUserExpertModeEnabled, appThemeText, onColorPickerChange, + onColorPickerComplete, + onColorSwatchPress, disabled, style, }) { @@ -271,6 +273,7 @@ export function MyColorPickerV2({ onColorPickerChange(color.hex); }} boundedThumb + onComplete={onColorPickerComplete} > {disabled && ( { pickerRef.current.setColor(color); onColorPickerChange(color); + onColorSwatchPress(); }} onLongPress={() => { let filteredColors = @@ -413,7 +417,7 @@ export function MyColorSwatch({ size, backgroundColor, style }) { borderRadius: 16, }, AppStyles.Shadow, - style + style, ]} /> ); diff --git a/src/Components/Slider/index.js b/src/Components/Slider/index.js index 27af680..2064e44 100644 --- a/src/Components/Slider/index.js +++ b/src/Components/Slider/index.js @@ -9,6 +9,7 @@ export default function MySlider({ minimumValue, maximumValue, inverted, + onSlidingComplete, }) { const appContext = useContext(AppContext); @@ -24,6 +25,7 @@ export default function MySlider({ maximumTrackTintColor={appContext.appTheme.slider.maximumTrackTintColor} thumbTintColor={appContext.appTheme.slider.thumbTintColor} step={1} + onSlidingComplete={onSlidingComplete} /> ); } diff --git a/src/Screens/Device/modals/AddSceneAction/LayerSelection/index.js b/src/Screens/Device/modals/AddSceneAction/LayerSelection/index.js index 667ba5d..266a951 100644 --- a/src/Screens/Device/modals/AddSceneAction/LayerSelection/index.js +++ b/src/Screens/Device/modals/AddSceneAction/LayerSelection/index.js @@ -87,7 +87,8 @@ export default function LayerSelectionModalContent({ navigation, route }) { onPress={() => { const newAction = NewAction( GetDevice(appContext.devices).selectedScene, - Constants.actionType.layers + Constants.actionType.layers, + { layers: selectedLayer } ); appContext.setDeviceSceneActions((arr) => [...arr, newAction]); diff --git a/src/Screens/Device/modals/AddSceneAction/index.js b/src/Screens/Device/modals/AddSceneAction/index.js index 0dafdba..72e1936 100644 --- a/src/Screens/Device/modals/AddSceneAction/index.js +++ b/src/Screens/Device/modals/AddSceneAction/index.js @@ -1,11 +1,17 @@ import { useContext } from "react"; import { Image, ScrollView, Text, View } from "react-native"; -import { AppContext, AppStyles, ModalContainer } from "../../../../utils"; +import { + AppContext, + AppStyles, + Constants, + ModalContainer, +} from "../../../../utils"; import MyIcon from "../../../../Components/Icon"; import { Divider } from "../../../../Components/Divider"; import { useTranslation } from "react-i18next"; import MyTag from "../../../../Components/Tag"; import MyPressable from "../../../../Components/Pressable"; +import { ActionTypeIconName } from "../../scene"; function Action({ text, @@ -79,7 +85,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { navigation.navigate("modalLayerSection", route.params)} deviceFirmwareVersion={deviceFirmwareVersion} @@ -88,7 +94,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} @@ -99,7 +105,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { text={t( "screens.device.scenes.modalAddSceneAction.actions.ambilight" )} - iconName="television-ambient-light" + iconName={ActionTypeIconName(Constants.actionType.ambilight)} imageSource={require("../../../../../assets/ambilight.gif")} onPress={() => console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} @@ -110,7 +116,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { text={t( "screens.device.scenes.modalAddSceneAction.actions.waitXSeconds" )} - iconName="timer-sand" + iconName={ActionTypeIconName(Constants.actionType.waitXSeconds)} onPress={() => console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} supportedFirmwareVersions={["1.0.1"]} @@ -120,7 +126,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { text={t( "screens.device.scenes.modalAddSceneAction.actions.waitUntilTimeX" )} - iconName="clock-time-eight-outline" + iconName={ActionTypeIconName(Constants.actionType.waitUntilTimeX)} onPress={() => console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} supportedFirmwareVersions={["1.0.1"]} @@ -128,7 +134,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} supportedFirmwareVersions={["1.0.1"]} @@ -138,7 +144,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { text={t( "screens.device.scenes.modalAddSceneAction.actions.timeControl" )} - iconName="timer-cog" + iconName={ActionTypeIconName(Constants.actionType.timeControl)} onPress={() => console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} supportedFirmwareVersions={["1.0.1"]} @@ -148,7 +154,9 @@ export default function AddSceneActionModalContent({ navigation, route }) { text={t( "screens.device.scenes.modalAddSceneAction.actions.waitForConfirmationWithKey" )} - iconName="gesture-tap-button" + iconName={ActionTypeIconName( + Constants.actionType.waitForConfirmationWithKey + )} onPress={() => console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} supportedFirmwareVersions={["1.0.0"]} @@ -158,7 +166,7 @@ export default function AddSceneActionModalContent({ navigation, route }) { text={t( "screens.device.scenes.modalAddSceneAction.actions.jumpToScene" )} - iconName="debug-step-over" + iconName={ActionTypeIconName(Constants.actionType.jumpToScene)} onPress={() => console.log("pressed action")} deviceFirmwareVersion={deviceFirmwareVersion} supportedFirmwareVersions={["1.0.0"]} diff --git a/src/Screens/Device/modals/EditActions/Lights/index.js b/src/Screens/Device/modals/EditActions/Lights/index.js index ec2b391..6f74711 100644 --- a/src/Screens/Device/modals/EditActions/Lights/index.js +++ b/src/Screens/Device/modals/EditActions/Lights/index.js @@ -21,11 +21,10 @@ import Animated, { useAnimatedStyle, useSharedValue, } from "react-native-reanimated"; -import { Divider } from "../../../../../Components/Divider"; import { MyIconButton } from "../../../../../Components/Button"; import { ColorPickerRef } from "reanimated-color-picker"; // used import EditActionAnimationsCardContent, { - EditActionAdjustmentContent, + EditActionAdjustmentsContent, } from ".."; import { useTranslation } from "react-i18next"; @@ -71,7 +70,7 @@ function LightModeDefaultColor({ export function LightsEditActionModalContent({ navigation, route }) { const appContext = useContext(AppContext); - const [lightModeDefaultColors, setLightModeDefaultColors] = useState([]); + const sharedLightModeDefaultColors = useSharedValue([]); const [selectedDefaultLightModeColor, setSelectedDefaultLightModeColor] = useState(0); @@ -89,24 +88,46 @@ export function LightsEditActionModalContent({ navigation, route }) { (a) => a.actionId === actionId ); + const [lightModeDefaultColors, setLightModeDefaultColors] = useState([]); + const selectedLightMode = supportedDeviceLightModes.find( (s) => s.id === selectedSceneAction.modeId ); useEffect(() => { if (colorPickerRef.current && selectedLightMode.defaults.length > 0) { - colorPickerRef.current.setColor(selectedLightMode.defaults[0]); + colorPickerRef.current.setColor( + selectedSceneAction.modeAdjustments.colors[0] + ); } }, [lightModeDefaultColors]); useEffect(() => { if (selectedLightMode !== undefined) { - sharedLightModeDefaultColors.value = selectedLightMode.defaults; - setLightModeDefaultColors(selectedLightMode.defaults); + sharedLightModeDefaultColors.value = + selectedSceneAction.modeAdjustments.colors; + setLightModeDefaultColors(selectedSceneAction.modeAdjustments.colors); setSelectedDefaultLightModeColor(0); } }, [selectedSceneAction.modeId]); + const saveColorsToModeAdjustments = () => { + appContext.setDeviceSceneActions((arr) => { + const newArr = [...arr]; + + const foundSceneActionIndex = arr.findIndex( + (a) => a.actionId === selectedSceneAction.actionId + ); + + if (foundSceneActionIndex !== -1) { + newArr[foundSceneActionIndex].modeAdjustments.colors = + sharedLightModeDefaultColors.value; + } + + return newArr; + }); + }; + return ( { - /*const newSelection = - selectedDefaultLightModeColor !== index - ? index - : undefined; - - setSelectedDefaultLightModeColor(newSelection); - - if (newSelection !== undefined) { - colorPickerRef.current.setColor( - sharedLightModeDefaultColors.value[index] - ); - }*/ - setSelectedDefaultLightModeColor(index); colorPickerRef.current.setColor( @@ -247,23 +255,17 @@ export function LightsEditActionModalContent({ navigation, route }) { sharedLightModeDefaultColors.value = newColors; } }} + onColorPickerComplete={() => saveColorsToModeAdjustments()} + onColorSwatchPress={() => saveColorsToModeAdjustments()} /> )} - {selectedLightMode.adjustments.length > 0 && ( - <> - {selectedLightMode.adjustments.map((adjustment, index) => ( - - - - ))} - - )} + )} @@ -306,6 +308,27 @@ export function LayersEditActionColorModeSelectionModalContent({ if (actionIndex !== -1) { newArr[actionIndex].modeId = item.id; + + const lightModeDefaultColors = + appContext.deviceFirmwareModes.lightModes.find( + (lM) => lM.id === item.id + ); + + if (lightModeDefaultColors !== undefined) { + if (lightModeDefaultColors.defaults !== undefined) { + newArr[actionIndex].modeAdjustments.colors = + appContext.deviceFirmwareModes.lightModes.find( + (lM) => lM.id === item.id + ).defaults; + } + } + + item.adjustments.forEach( + (adjustment) => + (newArr[actionIndex].modeAdjustments[ + adjustment.variableName + ] = adjustment.defaultValue) + ); } return newArr; diff --git a/src/Screens/Device/modals/EditActions/index.js b/src/Screens/Device/modals/EditActions/index.js index e6dfe1d..3903919 100644 --- a/src/Screens/Device/modals/EditActions/index.js +++ b/src/Screens/Device/modals/EditActions/index.js @@ -3,6 +3,7 @@ import Card from "../../../../Components/Card"; import { AppContext, AppStyles, + Constants, IsPlatformIos, ModalContainer, } from "../../../../utils"; @@ -23,8 +24,6 @@ export default function EditActionAnimationsCardContent({ const appContext = useContext(AppContext); const { t } = useTranslation(); - console.log("act", action); - const selectedLightAnimationIn = appContext.deviceFirmwareModes.lightAnimationsIn.find( (animation) => animation.id === action.animationInId @@ -67,15 +66,11 @@ export default function EditActionAnimationsCardContent({ } /> - {selectedLightAnimationIn.adjustments.length > 0 && - selectedLightAnimationIn.adjustments.map((adjustment, index) => ( - - ))} + - {selectedLightAnimationOut.adjustments.length > 0 && - selectedLightAnimationOut.adjustments.map((adjustment, index) => ( - - ))} + ); @@ -185,6 +176,14 @@ export function EditActionAnimationSelectionModalContent({ newArr[foundActionIndex][animationType] = item.id; + const type = + animationType === "animationInId" + ? "animationInAdjustment" + : "animationOutAdjustment"; + + newArr[foundActionIndex][type][item.adjustment.variableName] = + item.adjustment.defaultValue; + return newArr; }); }} @@ -196,44 +195,101 @@ export function EditActionAnimationSelectionModalContent({ ); } -export function EditActionAdjustmentContent({ +export function EditActionAdjustmentsContent({ + action, + adjustmentType, adjustment, - appThemeText, - appLanguage, + adjustments, }) { - const [sliderValue, setSliderValue] = useState(0); + if (adjustments === undefined && Object.keys(adjustment).length === 0) + return <>; - if (adjustment.type === "slider") { + if (adjustments !== undefined) { return ( - <> - - {adjustment.name[appLanguage]} - + { + if (item.type === "slider") { + return ( + + ); + } - - - - { - console.log(`change ${adjustment.variableName}`, v); - setSliderValue(v); - }} - value={sliderValue} - /> - - - - {sliderValue} - {adjustment.unitOfMeasurement} - - - - + return Item type not found; + }} + /> ); } - return <>; + return ( + + ); +} + +function EditActionSliderAdjustment({ action, adjustmentType, adjustment }) { + const appContext = useContext(AppContext); + + const type = + adjustmentType === "mode" + ? "modeAdjustments" + : adjustmentType === "animationIn" + ? "animationInAdjustment" + : "animationOutAdjustment"; + + const [sliderValue, setSliderValue] = useState( + action[type][adjustment.variableName] + ); + + return ( + <> + + {adjustment.name[appContext.appLanguage]} + + + + + + setSliderValue(v)} + value={sliderValue} + onSlidingComplete={(v) => + appContext.setDeviceSceneActions((arr) => { + const newArr = [...arr]; + + const foundActionIndex = arr.findIndex( + (a) => a.actionId === action.actionId + ); + + if (foundActionIndex !== -1) { + newArr[foundActionIndex][type][adjustment.variableName] = v; + } + + return newArr; + }) + } + /> + + + + {sliderValue} + {adjustment.unitOfMeasurement[appContext.appLanguage]} + + + + + ); } diff --git a/src/Screens/Device/scene.js b/src/Screens/Device/scene.js index 1e45be0..70f8d52 100644 --- a/src/Screens/Device/scene.js +++ b/src/Screens/Device/scene.js @@ -85,52 +85,46 @@ export default function SceneView({ navigation }) { iconName={"selection-search"} /> ) : ( - - item.actionId} - ListEmptyComponent={ - item.actionId} + ListEmptyComponent={ + + } + ListFooterComponent={ + + navigation.navigate("modalAddSceneAction", { + deviceFirmwareVersion: device.firmware.version, + }) + } + iconName="plus-circle-outline" + /> + } + renderItem={({ item }) => { + return ( + - } - ListFooterComponent={ - - navigation.navigate("modalAddSceneAction", { - deviceFirmwareVersion: device.firmware.version, - }) - } - iconName="plus-circle-outline" - /> - } - renderItem={({ item }) => { - console.log("item", item); - - return ( - - ); - }} - /> - + ); + }} + /> )} { + return ( + + {item.modeId === "" + ? "???" + : appContext.deviceFirmwareModes.lightModes.find( + (lM) => lM.id === item.modeId + ).name[appContext.appLanguage]} + + ); + }; + + const getAnimationText = (animationInOrOutList, itemId, itemAdjustment) => { + const usedAnimation = animationInOrOutList.find((lA) => lA.id === itemId); + + return `${usedAnimation.name[appContext.appLanguage]} (${ + itemAdjustment[usedAnimation.adjustment.variableName] + }${usedAnimation.adjustment.unitOfMeasurement[appContext.appLanguage]})`; + }; + + const ListItemAdjustments = () => { + let adjustments = []; + + if ( + item.type === Constants.actionType.layers && + item.modeAdjustments.layers !== undefined + ) { + adjustments.push( + + + {appContext.deviceFirmwareModes.lightModes.find( + (lM) => lM.id === item.modeId + ).defaults.length === 0 + ? `Apply to layer ${item.modeAdjustments.layers.join(", ")}` + : ` Set layer ${item.modeAdjustments.layers.join(", ")} to ${ + item.modeAdjustments.colors.length === 0 ? "???" : "" + }`} + + + {item.modeAdjustments.colors !== undefined && + item.modeAdjustments.colors.map((color, index) => ( + + ))} + + ); + } + + if ( + item.animationInId !== Constants.defaultAnimationId || + item.animationOutId !== Constants.defaultAnimationId + ) { + let inAndOutAnimation = []; + + if (item.animationInId !== Constants.defaultAnimationId) { + inAndOutAnimation.push( + getAnimationText( + appContext.deviceFirmwareModes.lightAnimationsIn, + item.animationInId, + item.animationInAdjustment + ) + ); + } + + if (item.animationOutId !== Constants.defaultAnimationId) { + inAndOutAnimation.push( + getAnimationText( + appContext.deviceFirmwareModes.lightAnimationsOut, + item.animationOutId, + item.animationOutAdjustment + ) + ); + } + + adjustments.push( + + + + {inAndOutAnimation.join(", ")} + + + ); + } + + return adjustments.map((adjustment, index) => ( + + {adjustment} + + )); + }; + return ( - + navigation.navigate("modalLayersEditAction", { @@ -211,41 +300,17 @@ function ActionListItem({ justifyContent: "space-between", }} > - {console.log("itemtype", item.type)} - - + + - - {item.modeId === "" ? "???" : item.modeId} - + - - - Set to - - - - - - + {item.modeId !== "" && } diff --git a/src/utils.js b/src/utils.js index 7904d23..040705f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -26,11 +26,18 @@ export const Constants = { layers: 0, ambilight: 1, motor: 2, + waitXSeconds: 3, + waitUntilTimeX: 4, + stop: 5, + timeControl: 6, + waitForConfirmationWithKey: 7, + jumpToScene: 8, }, globals: { max_device_name_length: 20, max_scene_name_length: 20, }, + defaultAnimationId: "00000000-0000-0000-0000-000000000000", // used id for -> No animation selected }; export const AppStyles = StyleSheet.create({ @@ -219,7 +226,7 @@ const devDevicesFirmwareModes = { de: "Zufällig", en: "Random", }, - defaults: ["pink", "orange", "blue"], + defaults: ["red", "orange", "blue"], adjustments: [ { type: "slider", @@ -231,7 +238,11 @@ const devDevicesFirmwareModes = { }, min: 0, max: 6, - unitOfMeasurement: "s", + defaultValue: 2, + unitOfMeasurement: { + de: "s", + en: "s", + }, }, ], }, @@ -254,7 +265,11 @@ const devDevicesFirmwareModes = { }, min: 0, max: 100, - unitOfMeasurement: "s", + defaultValue: 45, + unitOfMeasurement: { + de: "s", + en: "s", + }, }, { type: "slider", @@ -266,7 +281,11 @@ const devDevicesFirmwareModes = { }, min: 1, max: 10, - unitOfMeasurement: "s", + defaultValue: 8, + unitOfMeasurement: { + de: "s", + en: "s", + }, }, ], }, @@ -279,7 +298,7 @@ const devDevicesFirmwareModes = { de: "Keine", en: "None", }, - adjustments: [], + adjustment: {}, }, { id: "6c5570da-ec53-4788-a8cd-03c724eb81b8", @@ -288,20 +307,22 @@ const devDevicesFirmwareModes = { de: "Aufblenden", en: "Fade in", }, - adjustments: [ - { - type: "slider", - variableName: "duration", - name: { - de: "Dauer", - en: "Duration", - }, - iconName: "repeat-variant", - min: 1, - max: 60, - unitOfMeasurement: "s", + adjustment: { + type: "slider", + variableName: "duration", + name: { + de: "Dauer", + en: "Duration", }, - ], + iconName: "repeat-variant", + min: 1, + max: 60, + defaultValue: 30, + unitOfMeasurement: { + de: "s", + en: "s", + }, + }, }, ], lightAnimationsOut: [ @@ -312,7 +333,7 @@ const devDevicesFirmwareModes = { de: "Keine", en: "None", }, - adjustments: [], + adjustment: {}, }, { id: "cb5b791e-213c-4684-9585-b0c42cbfafb5", @@ -321,20 +342,22 @@ const devDevicesFirmwareModes = { de: "Ausblenden", en: "Fade out", }, - adjustments: [ - { - type: "slider", - variableName: "duration", - name: { - de: "Dauer", - en: "Duration", - }, - iconName: "repeat-variant", - min: 1, - max: 60, - unitOfMeasurement: "s", + adjustment: { + type: "slider", + variableName: "duration", + name: { + de: "Dauer", + en: "Duration", }, - ], + iconName: "repeat-variant", + min: 1, + max: 60, + defaultValue: 30, + unitOfMeasurement: { + de: "s", + en: "s", + }, + }, }, ], motorModes: [ @@ -351,8 +374,6 @@ const devDevicesFirmwareModes = { ], }; -export const DevDeviceId = "1f21a12a-0bec-4336-99bb-df3f9fc9f537"; - // this data is transmitted from the device to the user app const devDevices = [ { @@ -394,27 +415,40 @@ export function NewDeviceScene(name) { }; } +// preview const devDeviceSceneActions = [ { actionId: "", // random id sceneId: "", type: "", // layers, ambilight, motor modeId: "", + // affected layers, animation speed... + modeAdjustments: { + layers: [0, 1], + colors: ["#fff", "#000"], + }, animationInId: "", animationOutId: "", - adjustments: [], // affected layers, animation speed... + animationInAdjustment: { + duration: 32, + }, + animationOutAdjustment: { + duration: 32, + }, }, ]; -export function NewAction(sceneId, actionType) { +export function NewAction(sceneId, actionType, modeAdjustments) { return { actionId: GetUuid(), sceneId: sceneId, type: actionType, // layers, ambilight, motor modeId: "", + modeAdjustments: modeAdjustments, animationInId: "00000000-0000-0000-0000-000000000000", // default animation id for -> No animation selected + animationInAdjustment: {}, animationOutId: "00000000-0000-0000-0000-000000000000", // default animation id for -> No animation selected - adjustments: [], + animationOutAdjustment: {}, }; }