action wait

main
alex 2023-08-09 20:07:39 +00:00
parent e45a2cf42e
commit 13ca11b01a
10 changed files with 549 additions and 31 deletions

14
App.js
View File

@ -38,6 +38,7 @@ import { EditActionAnimationSelectionModalContent } from "./src/Screens/Device/m
import MotorEditActionModalContent, {
MotorEditActionMotorModeSelectionModalContent,
} from "./src/Screens/Device/modals/EditActions/Motor";
import WaitXSecondsEditActionModalContent from "./src/Screens/Device/modals/EditActions/Wait";
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
@ -234,6 +235,19 @@ export function MyApp() {
}
/>
<Stack.Screen
name="modalWaitEditAction"
component={WaitXSecondsEditActionModalContent}
options={({ navigation }) =>
options({
navigation: navigation,
pageTitle: t(
"screens.device.scenes.editActions.modalWaitEditAction.pageTitle"
),
})
}
/>
<Stack.Screen
name="modalUpdateSceneName"
component={UpdateSceneNameModalContent}

View File

@ -47,7 +47,8 @@
"multipleLayers": "Ebenen"
}
},
"ambilight": "Umgebungslicht setzen auf"
"ambilight": "Umgebungslicht setzen auf",
"wait": "Warten"
},
"modalChooseScene": {
"pageTitle": "Wähle eine Szene aus",
@ -68,7 +69,7 @@
"layers": "Ebenen",
"motor": "Motor",
"ambilight": "Ambilight",
"waitXSeconds": "Warte X Sekunden",
"wait": "Warte",
"waitUntilTimeX": "Warten bis Zeit X",
"stop": "Stop",
"timeControl": "Zeitsteuerung",
@ -124,6 +125,26 @@
},
"modalMotorEditActionMotorModeSelection": {
"pageTitle": "Motormodus wählen"
},
"modalWaitEditAction": {
"pageTitle": "Dauer der Wartezeit",
"waitDescription": "Das Gerät wird die angegebene Zeit warten, bevor es die nächste Aktion startet.",
"wordAndForBetterSceneActionListAdjustmentReading": "und",
"hours": {
"bottomModalHeaderTitle": "Stunde auswählen",
"singular": "Stunde",
"plural": "Stunden"
},
"minutes": {
"bottomModalHeaderTitle": "Minute auswählen",
"singular": "Minute",
"plural": "Minuten"
},
"seconds": {
"bottomModalHeaderTitle": "Sekunde auswählen",
"singular": "Sekunde",
"plural": "Sekunden"
}
}
},
"modalUpdateSceneName": {

View File

@ -47,7 +47,8 @@
"multipleLayers": "layers"
}
},
"ambilight": "Set ambilight to"
"ambilight": "Set ambilight to",
"wait": "Wait"
},
"modalChooseScene": {
"pageTitle": "Choose a scene",
@ -68,7 +69,7 @@
"layers": "Layers",
"motor": "Motor",
"ambilight": "Ambilight",
"waitXSeconds": "Wait X seconds",
"wait": "Wait",
"waitUntilTimeX": "Wait until time X",
"stop": "Stop",
"timeControl": "Time control",
@ -124,6 +125,26 @@
},
"modalMotorEditActionMotorModeSelection": {
"pageTitle": "Choose motor mode"
},
"modalWaitEditAction": {
"pageTitle": "Duration to wait",
"waitDescription": "The device will wait the specified time before starting the next action.",
"wordAndForBetterSceneActionListAdjustmentReading": "and",
"hours": {
"bottomModalHeaderTitle": "Choose hour",
"singular": "Hour",
"plural": "Hours"
},
"minutes": {
"bottomModalHeaderTitle": "Choose minute",
"singular": "Minute",
"plural": "Minutes"
},
"seconds": {
"bottomModalHeaderTitle": "Choose second",
"singular": "Second",
"plural": "Seconds"
}
}
},
"modalUpdateSceneName": {

View File

@ -225,11 +225,16 @@ export function MyPickerModalListItem({
itemName,
itemSelected,
disabled,
pressableBackgroundColor,
}) {
const appContext = useContext(AppContext);
return (
<MyPressable onPress={onPress} disabled={disabled}>
<MyPressable
backgroundColor={pressableBackgroundColor}
onPress={onPress}
disabled={disabled}
>
<View
style={{
flexDirection: "row",
@ -308,6 +313,77 @@ export function MyTextInputModalContent({
);
}
export function MyBottomSheetModal({
children,
isOpen,
closeModal,
modalHeight,
headerTitle,
}) {
const appContext = useContext(AppContext);
return (
<Modal
visible={isOpen}
transparent
animationType="slide"
style={{ flex: 1 }}
onRequestClose={() => closeModal()}
>
<TouchableWithoutFeedback onPress={() => closeModal()}>
<View style={{ flex: 1 }} />
</TouchableWithoutFeedback>
<View>
<View
style={{
backgroundColor: appContext.appTheme.card.backgroundColor,
height: modalHeight,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
paddingTop: 12,
shadowRadius: 8,
shadowOffset: {
width: 0,
height: -10,
},
shadowColor: "#000000",
elevation: 6,
}}
>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
marginLeft: 10,
marginRight: 10,
}}
>
<Text
style={[
{ color: appContext.appTheme.text, fontWeight: "bold" },
AppStyles.typography16,
]}
>
{headerTitle}
</Text>
<MyIconButton
style={{ padding: 2 }}
iconSize={24}
iconColor={appContext.appTheme.icon}
iconName="close"
onPress={() => closeModal()}
/>
</View>
{children}
</View>
</View>
</Modal>
);
}
/*
export function MyPickerModal({ isOpen, setIsOpen, items, searchFilter }) {
const appContext = useContext(AppContext);

View File

@ -8,6 +8,7 @@ export default function MyTextInput({
textMaxLength,
value,
onChangeText,
inputMode,
}) {
const appContext = useContext(AppContext);
@ -17,6 +18,7 @@ export default function MyTextInput({
{textTitle}
</Text>
<TextInput
inputMode={inputMode === undefined ? "text" : inputMode}
style={{
height: 40,
color: appContext.appTheme.text,

View File

@ -151,11 +151,15 @@ export default function AddSceneActionModalContent({ navigation, route }) {
/>
<Action
text={t(
"screens.device.scenes.modalAddSceneAction.actions.waitXSeconds"
)}
iconName={ActionTypeIconName(Constants.actionType.waitXSeconds)}
onPress={() => console.log("pressed action")}
text={t("screens.device.scenes.modalAddSceneAction.actions.wait")}
iconName={ActionTypeIconName(Constants.actionType.wait)}
onPress={() =>
handleCreateAction(
Constants.actionType.wait,
{ hours: 0, minutes: 0, seconds: 0 },
"modalWaitEditAction"
)
}
deviceFirmwareVersion={deviceFirmwareVersion}
supportedFirmwareVersions={["1.0.1"]}
/>

View File

@ -33,10 +33,7 @@ import {
EditActionAnimationsCardContent,
RenderHeaderRight,
} from "..";
import {
MyDotsModal,
MyPickerModalListItem,
} from "../../../../../Components/Modal";
import { MyPickerModalListItem } from "../../../../../Components/Modal";
// This component is used by layers and ambilight
export default function LightsEditActionModalContent({ navigation, route }) {

View File

@ -0,0 +1,301 @@
import { useCallback, useContext, useState } from "react";
import { Dimensions, Text, TouchableOpacity, View } from "react-native";
import { AppContext, AppStyles, ModalContainer } from "../../../../../utils";
import { FlatList } from "react-native";
import {
MyBottomSheetModal,
MyPickerModalListItem,
} from "../../../../../Components/Modal";
import { useTranslation } from "react-i18next";
import { useFocusEffect } from "@react-navigation/native";
import { RenderHeaderRight } from "..";
const dataHours = [
{ number: "00" },
{ number: "01" },
{ number: "02" },
{ number: "03" },
{ number: "04" },
{ number: "05" },
{ number: "06" },
{ number: "07" },
{ number: "08" },
{ number: "09" },
{ number: "10" },
{ number: "11" },
{ number: "12" },
{ number: "13" },
{ number: "14" },
{ number: "15" },
{ number: "16" },
{ number: "17" },
{ number: "18" },
{ number: "19" },
{ number: "20" },
{ number: "21" },
{ number: "22" },
{ number: "23" },
];
const dataMinutesAndSeconds = [
{ number: "00" },
{ number: "01" },
{ number: "02" },
{ number: "03" },
{ number: "04" },
{ number: "05" },
{ number: "06" },
{ number: "07" },
{ number: "08" },
{ number: "09" },
{ number: "10" },
{ number: "15" },
{ number: "20" },
{ number: "25" },
{ number: "30" },
{ number: "35" },
{ number: "40" },
{ number: "45" },
{ number: "50" },
{ number: "55" },
];
const windowHeight = Dimensions.get("window").height;
const modalHeight = windowHeight * 0.6; // 60 % of device screen
export default function WaitEditActionModalContent({ navigation, route }) {
const appContext = useContext(AppContext);
const { t } = useTranslation();
const { action } = route.params;
console.log("params", route.params);
const [selectedHours, setSelectedHours] = useState(
action.modeAdjustments.hours
);
const [selectedMinutes, setSelectedMinutes] = useState(
action.modeAdjustments.minutes
);
const [selectedSeconds, setSelectedSeconds] = useState(
action.modeAdjustments.seconds
);
const NumberSelection = ({
headerTitle,
data,
numberDescription,
selectedNumber,
setSelectedNumber,
action,
timeUnit,
}) => {
return (
<View style={{ alignItems: "center", width: 70 }}>
<MyNumberModal
headerTitle={headerTitle}
numberDescription={numberDescription}
data={data}
selectedNumber={selectedNumber}
setSelectedNumber={setSelectedNumber}
action={action}
timeUnit={timeUnit}
/>
</View>
);
};
const NumberDivider = () => {
return (
<Text
style={[
{ color: appContext.appTheme.textSecondary },
AppStyles.typography20,
]}
>
:
</Text>
);
};
useFocusEffect(
useCallback(() => {
navigation.setOptions({
headerRight: () => (
<RenderHeaderRight
action={action}
appContext={appContext}
navigation={navigation}
t={t}
/>
),
});
}, [])
);
return (
<ModalContainer>
<View
style={{
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
marginTop: 50,
gap: 20,
}}
>
<NumberSelection
numberDescription={
selectedHours === 1
? t(
"screens.device.scenes.editActions.modalWaitEditAction.hours.singular"
)
: t(
"screens.device.scenes.editActions.modalWaitEditAction.hours.plural"
)
}
headerTitle={t(
"screens.device.scenes.editActions.modalWaitEditAction.hours.bottomModalHeaderTitle"
)}
data={dataHours}
selectedNumber={selectedHours}
setSelectedNumber={setSelectedHours}
action={action}
timeUnit={"hours"}
/>
<NumberDivider />
<NumberSelection
numberDescription={
selectedMinutes === 1
? t(
"screens.device.scenes.editActions.modalWaitEditAction.minutes.singular"
)
: t(
"screens.device.scenes.editActions.modalWaitEditAction.minutes.plural"
)
}
headerTitle={t(
"screens.device.scenes.editActions.modalWaitEditAction.minutes.bottomModalHeaderTitle"
)}
data={dataMinutesAndSeconds}
selectedNumber={selectedMinutes}
setSelectedNumber={setSelectedMinutes}
action={action}
timeUnit={"minutes"}
/>
<NumberDivider />
<NumberSelection
numberDescription={
selectedSeconds === 1
? t(
"screens.device.scenes.editActions.modalWaitEditAction.seconds.singular"
)
: t(
"screens.device.scenes.editActions.modalWaitEditAction.seconds.plural"
)
}
headerTitle={t(
"screens.device.scenes.editActions.modalWaitEditAction.seconds.bottomModalHeaderTitle"
)}
data={dataMinutesAndSeconds}
selectedNumber={selectedSeconds}
setSelectedNumber={setSelectedSeconds}
action={action}
timeUnit={"seconds"}
/>
</View>
<View style={{ marginTop: 20, justifyContent: "center" }}>
<Text style={{ color: appContext.appTheme.text, textAlign: "center" }}>
{t(
"screens.device.scenes.editActions.modalWaitEditAction.waitDescription"
)}
</Text>
</View>
</ModalContainer>
);
}
export function MyNumberModal({
headerTitle,
numberDescription,
data,
selectedNumber,
setSelectedNumber,
action,
timeUnit,
}) {
const appContext = useContext(AppContext);
const [isNumberModalOpen, setIsNumberModalOpen] = useState(false);
return (
<>
<TouchableOpacity
onPress={() => setIsNumberModalOpen(true)}
style={{ alignItems: "center" }}
>
<Text
style={[{ color: appContext.appTheme.text }, AppStyles.typography20]}
>
{data.find((d) => parseInt(d.number, 10) === selectedNumber).number}
</Text>
<Text
style={[
{ color: appContext.appTheme.textSecondary },
AppStyles.typography14,
]}
>
{numberDescription}
</Text>
</TouchableOpacity>
<MyBottomSheetModal
isOpen={isNumberModalOpen}
closeModal={() => setIsNumberModalOpen(false)}
headerTitle={headerTitle}
modalHeight={modalHeight}
>
<FlatList
data={data}
keyExtractor={(item) => item.number}
renderItem={({ item }) => (
<MyPickerModalListItem
pressableBackgroundColor={
appContext.appTheme.card.backgroundColor
}
itemName={item.number}
onPress={() => {
setSelectedNumber(parseInt(item.number, 10));
appContext.setDeviceSceneActions((arr) => {
const newArr = [...arr];
const actionIndex = newArr.findIndex(
(a) => a.actionId === action.actionId
);
if (actionIndex !== -1) {
newArr[actionIndex].modeAdjustments[timeUnit] = parseInt(
item.number,
10
);
}
return newArr;
});
}}
itemSelected={selectedNumber === parseInt(item.number, 10)}
/>
)}
/>
</MyBottomSheetModal>
</>
);
}

View File

@ -242,17 +242,23 @@ function ActionListItem({ drag, navigation, device, item }) {
};
const ListItemTitle = () => {
let title = "???";
if (item.type === Constants.actionType.wait) {
title = t("screens.device.scenes.modalAddSceneAction.actions.wait");
} else if (item.modeId !== "") {
title = itemModeList.find((m) => m.id === item.modeId).name[
appContext.appLanguage
];
}
return (
<Text
style={{
color: appContext.appTheme.colors.primary,
}}
>
{item.modeId === ""
? "???"
: itemModeList.find((m) => m.id === item.modeId).name[
appContext.appLanguage
]}
{title}
</Text>
);
};
@ -351,8 +357,76 @@ function ActionListItem({ drag, navigation, device, item }) {
case Constants.actionType.motor:
navigateTo = "modalMotorEditAction";
itemModeList = appContext.deviceFirmwareModes.motorModes;
break;
case Constants.actionType.wait:
navigateTo = "modalWaitEditAction";
//adjustments.push(<ListItem text={"Motor"} />);
let msg = "";
const hours = item.modeAdjustments.hours;
const minutes = item.modeAdjustments.minutes;
const seconds = item.modeAdjustments.seconds;
const hoursText =
hours === 1
? t(
"screens.device.scenes.editActions.modalWaitEditAction.hours.singular"
)
: t(
"screens.device.scenes.editActions.modalWaitEditAction.hours.plural"
);
const minutesText =
minutes === 1
? t(
"screens.device.scenes.editActions.modalWaitEditAction.minutes.singular"
)
: t(
"screens.device.scenes.editActions.modalWaitEditAction.minutes.plural"
);
const secondsText =
seconds === 1
? t(
"screens.device.scenes.editActions.modalWaitEditAction.seconds.singular"
)
: t(
"screens.device.scenes.editActions.modalWaitEditAction.seconds.plural"
);
const wordAndForBetterSceneActionListAdjustmentReadingText = t(
"screens.device.scenes.editActions.modalWaitEditAction.wordAndForBetterSceneActionListAdjustmentReading"
);
if (hours > 0) {
msg += `${hours} ${hoursText}`;
}
if (minutes > 0) {
if (msg.length > 0) {
msg += ", ";
}
if (hours > 0 && seconds === 0) {
msg += ` ${wordAndForBetterSceneActionListAdjustmentReadingText} `;
}
msg += `${minutes} ${minutesText}`;
}
if (seconds > 0) {
if (msg.length > 0) {
msg += ` ${wordAndForBetterSceneActionListAdjustmentReadingText} `;
}
msg += `${seconds} ${secondsText}`;
}
if (msg.length === 0) {
msg = `0 ${secondsText}`;
}
adjustments.push(<ListItem text={<Text>{msg}</Text>} />);
break;
default:
console.log("item type not defined" + item.type);
@ -395,6 +469,22 @@ function ActionListItem({ drag, navigation, device, item }) {
);
}
const renderAdjustments = () => {
if (item.modeId === "" && item.type !== Constants.actionType.wait) {
return null;
}
return (
<>
{adjustments.map((adjustment, index) => (
<View key={index} style={{ flexDirection: "row" }}>
{adjustment}
</View>
))}
</>
);
};
return (
<View style={{ marginLeft: 15, marginRight: 15 }}>
<TouchableOpacity
@ -419,15 +509,7 @@ function ActionListItem({ drag, navigation, device, item }) {
<View style={{ marginLeft: 12 }}>
<ListItemTitle />
{item.modeId !== "" && (
<>
{adjustments.map((adjustment, index) => (
<View key={index} style={{ flexDirection: "row" }}>
{adjustment}
</View>
))}
</>
)}
{renderAdjustments()}
</View>
</View>
</View>
@ -462,7 +544,7 @@ export function ActionTypeIconName(actionType) {
case Constants.actionType.motor:
iconName = "axis-z-rotate-counterclockwise";
break;
case Constants.actionType.waitXSeconds:
case Constants.actionType.wait:
iconName = "timer-sand";
break;
case Constants.actionType.waitUntilTimeX:

View File

@ -27,7 +27,7 @@ export const Constants = {
layers: 0,
ambilight: 1,
motor: 2,
waitXSeconds: 3,
wait: 3,
waitUntilTimeX: 4,
stop: 5,
timeControl: 6,