650 lines
20 KiB
JavaScript
650 lines
20 KiB
JavaScript
import "react-native-gesture-handler";
|
|
import { StatusBar } from "expo-status-bar";
|
|
import { Text, View } from "react-native";
|
|
import { createDrawerNavigator } from "@react-navigation/drawer";
|
|
import { DefaultTheme, NavigationContainer } from "@react-navigation/native";
|
|
import SideBar from "./src/Components/SideBar";
|
|
import {
|
|
AppContext,
|
|
AppProvider,
|
|
AppStyles,
|
|
Constants,
|
|
GetDataFromList,
|
|
GetMultipleData,
|
|
IsPlatformIos,
|
|
} from "./src/utils";
|
|
import {
|
|
Suspense,
|
|
lazy,
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useState,
|
|
} from "react";
|
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
import "./i18n";
|
|
import DeviceScreen from "./src/Screens/Device";
|
|
import { createStackNavigator } from "@react-navigation/stack";
|
|
import { TouchableOpacity } from "react-native";
|
|
import MyIcon from "./src/Components/Icon";
|
|
import { useTranslation } from "react-i18next";
|
|
import * as SplashScreen from "expo-splash-screen";
|
|
|
|
/*
|
|
This screens shouldn't be loaded lazy as it one of the first screens the user sees
|
|
*/
|
|
|
|
import OnboardingScreen from "./src/Screens/Onboarding/Onboarding";
|
|
import NoDevicesConnectedScreen from "./src/Screens/NoDevicesConnected";
|
|
/*
|
|
This screens should be loaded lazy as they are they not seen by the user on startup
|
|
*/
|
|
const SettingsScreen = lazy(() => import("./src/Screens/Settings"));
|
|
const HelpScreen = lazy(() => import("./src/Screens/Help"));
|
|
const OpenSourceLicensesModalContent = lazy(() =>
|
|
import("./src/Screens/Settings/modals/openSourceLicences")
|
|
);
|
|
const MotorEditActionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/EditActions/Motor")
|
|
);
|
|
const MotorEditActionMotorModeSelectionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/EditActions/Motor").then((module) => ({
|
|
default: module.MotorEditActionMotorModeSelectionModalContent,
|
|
}))
|
|
);
|
|
const WaitXSecondsEditActionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/EditActions/Wait")
|
|
);
|
|
const StopEditActionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/EditActions/Stop")
|
|
);
|
|
const SearchForNewDevicesModalContent = lazy(() =>
|
|
import("./src/Screens/SearchForNewDevices")
|
|
);
|
|
const HelpCenterModalContent = lazy(() =>
|
|
import("./src/Screens/Help/modals/HelpCenter")
|
|
);
|
|
const FeedbackStepsModalContent = lazy(() =>
|
|
import("./src/Screens/Help/modals/Feedback/steps")
|
|
);
|
|
const GiveFeedbackModalContent = lazy(() =>
|
|
import("./src/Screens/Help/modals/Feedback")
|
|
);
|
|
const FeedbackFinishedModalContent = lazy(() =>
|
|
import("./src/Screens/Help/modals/Feedback/finished")
|
|
);
|
|
const SettingsAppColorSchemeModalContent = lazy(() =>
|
|
import("./src/Screens/Settings/modals/appColorScheme")
|
|
);
|
|
const SettingsAppLanguageModalContent = lazy(() =>
|
|
import("./src/Screens/Settings/modals/appLanguage")
|
|
);
|
|
const ChooseSceneModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/ChooseScene")
|
|
);
|
|
const CreateSceneModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/ChooseScene/CreateScene")
|
|
);
|
|
const AddSceneActionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/AddSceneAction")
|
|
);
|
|
const LayerSelectionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/AddSceneAction/LayerSelection")
|
|
);
|
|
const UpdateSceneNameModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/UpdateSceneName")
|
|
);
|
|
const SettingsChangeDeviceDisplayNameModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/SettingsChangeDeviceDisplayName")
|
|
);
|
|
const LightsEditActionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/EditActions/Lights")
|
|
);
|
|
const LightsEditActionColorModeSelectionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/EditActions/Lights").then((module) => ({
|
|
default: module.LightsEditActionColorModeSelectionModalContent,
|
|
}))
|
|
);
|
|
const EditActionAnimationSelectionModalContent = lazy(() =>
|
|
import("./src/Screens/Device/modals/EditActions")
|
|
);
|
|
|
|
const Drawer = createDrawerNavigator();
|
|
const Stack = createStackNavigator();
|
|
|
|
// Keep the splash screen visible while we fetch resources
|
|
SplashScreen.preventAutoHideAsync();
|
|
|
|
export function MyApp() {
|
|
const appContext = useContext(AppContext);
|
|
const { t } = useTranslation();
|
|
|
|
const [appIsReady, setAppIsReady] = useState(false);
|
|
const [showOnboarding, setShowOnboarding] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const loadData = async () => {
|
|
const data = await GetMultipleData([
|
|
"appLanguage",
|
|
"appColorScheme",
|
|
"userExpertMode",
|
|
"userDeveloperMode",
|
|
"userColorSwatchesFavorites",
|
|
]);
|
|
|
|
const appLanguage = GetDataFromList(data, "appLanguage");
|
|
const appColorScheme = GetDataFromList(data, "appColorScheme");
|
|
const userExpertMode = GetDataFromList(data, "userExpertMode");
|
|
const userDeveloperMode = GetDataFromList(data, "userDeveloperMode");
|
|
const userColorSwatchesFavorites = GetDataFromList(
|
|
data,
|
|
"userColorSwatchesFavorites"
|
|
);
|
|
|
|
// if the app language is not set we know that the user is using the app for the first time
|
|
if (appLanguage === null) {
|
|
setShowOnboarding(true);
|
|
}
|
|
|
|
appContext.setAppLanguage(
|
|
appLanguage === null ? Constants.defaultLanguage : appLanguage
|
|
);
|
|
appContext.setAppColorScheme(
|
|
appColorScheme === null ? "auto" : appColorScheme
|
|
);
|
|
|
|
appContext.setIsUserExpertModeEnabled(
|
|
userExpertMode == null ? false : userExpertMode
|
|
);
|
|
|
|
appContext.setUserIsDeveloperModeEnabled(
|
|
userDeveloperMode == null ? false : userDeveloperMode
|
|
);
|
|
|
|
appContext.setUserColorSwatchesFavorites(
|
|
userColorSwatchesFavorites === null
|
|
? Constants.defaultColorSwatchesFavorites
|
|
: userColorSwatchesFavorites
|
|
);
|
|
|
|
setAppIsReady(true);
|
|
};
|
|
|
|
loadData();
|
|
}, []);
|
|
|
|
const options = ({ navigation, pageTitle }) => {
|
|
return getScreenStackOptions(
|
|
navigation,
|
|
pageTitle,
|
|
appContext.appTheme.text,
|
|
appContext.appTheme.backgroundColor,
|
|
true
|
|
);
|
|
};
|
|
|
|
const navigatonTheme = {
|
|
...DefaultTheme,
|
|
colors: {
|
|
...DefaultTheme.colors,
|
|
background: appContext.appTheme.backgroundColor,
|
|
border: "transparent",
|
|
},
|
|
};
|
|
|
|
const onLayoutRootView = useCallback(async () => {
|
|
if (appIsReady) {
|
|
// This tells the splash screen to hide immediately! If we call this after
|
|
// `setAppIsReady`, then we may see a blank screen while the app is
|
|
// loading its initial state and rendering its first pixels. So instead,
|
|
// we hide the splash screen once we know the root view has already
|
|
// performed layout.
|
|
await SplashScreen.hideAsync();
|
|
}
|
|
}, [appIsReady]);
|
|
|
|
if (!appIsReady) return null;
|
|
|
|
return (
|
|
<SafeAreaView style={{ flex: 1 }} onLayout={onLayoutRootView}>
|
|
{showOnboarding ? (
|
|
<OnboardingScreen onContinue={() => setShowOnboarding(false)} />
|
|
) : (
|
|
<>
|
|
<NavigationContainer theme={navigatonTheme}>
|
|
<Stack.Navigator screenOptions={{ headerTitleAlign: "center" }}>
|
|
<Stack.Screen
|
|
name="drawer"
|
|
component={MyDrawer}
|
|
options={{ headerShown: false }}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalChooseScene"
|
|
component={ChooseSceneModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.modalChooseScene.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalCreateScene"
|
|
component={CreateSceneModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.modalCreateScene.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalAddSceneAction"
|
|
component={AddSceneActionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.modalAddSceneAction.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalLayerSelection"
|
|
component={LayerSelectionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.modalLayerSelection.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalLightsEditAction"
|
|
component={LightsEditActionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalLightsEditActionColorModeSelection"
|
|
component={LightsEditActionColorModeSelectionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.editActions.modalLightsEditActionColorModeSelection.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalEditActionAnimationInOrOutSelection"
|
|
component={EditActionAnimationSelectionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalMotorEditAction"
|
|
component={MotorEditActionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.editActions.modalMotorEditAction.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalMotorEditActionMotorModeSelection"
|
|
component={MotorEditActionMotorModeSelectionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.editActions.modalMotorEditActionMotorModeSelection.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalWaitEditAction"
|
|
component={WaitXSecondsEditActionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.editActions.modalWaitEditAction.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalStopEditAction"
|
|
component={StopEditActionModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.editActions.modalStopEditAction.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalUpdateSceneName"
|
|
component={UpdateSceneNameModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.scenes.modalUpdateSceneName.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalHelpCenter"
|
|
component={HelpCenterModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t("screens.help.modalHelpCenter.pageTitle"),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalGiveFeedback"
|
|
component={GiveFeedbackModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t("screens.help.modalGiveFeedback.pageTitle"),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalFeedbackSteps"
|
|
component={FeedbackStepsModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t("screens.help.modalFeedbackSteps.pageTitle"),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalFeedbackFinished"
|
|
component={FeedbackFinishedModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.help.modalFeedbackFinished.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalSettingsAppColorScheme"
|
|
component={SettingsAppColorSchemeModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.settings.cardGeneral.modalAppColorSchemePicker.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalSettingsAppLanguage"
|
|
component={SettingsAppLanguageModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.settings.cardGeneral.modalLanguagePageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalOpenSourceLicences"
|
|
component={OpenSourceLicensesModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.settings.modalOpenSourceLicences.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalSettingsChangeDeviceDisplayName"
|
|
component={SettingsChangeDeviceDisplayNameModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t(
|
|
"screens.device.settings.modalSettingsChangeDeviceDisplayName.pageTitle"
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
|
|
<Stack.Screen
|
|
name="modalSearchForNewDevices"
|
|
component={SearchForNewDevicesModalContent}
|
|
options={({ navigation }) =>
|
|
options({
|
|
navigation: navigation,
|
|
pageTitle: t("screens.modalSearchForNewDevices.pageTitle"),
|
|
})
|
|
}
|
|
/>
|
|
</Stack.Navigator>
|
|
</NavigationContainer>
|
|
|
|
<StatusBar
|
|
backgroundColor={appContext.appTheme.backgroundColor}
|
|
style={appContext.appTheme._id === "dark" ? "light" : "dark"}
|
|
/>
|
|
</>
|
|
)}
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
// This is for the left sidebar navigation
|
|
function MyDrawer() {
|
|
const appContext = useContext(AppContext);
|
|
|
|
return (
|
|
<Drawer.Navigator
|
|
screenOptions={{
|
|
headerShown: false,
|
|
//headerStyle: {
|
|
// backgroundColor: appContext.appTheme.backgroundColor,
|
|
//},
|
|
//headerTintColor: appContext.appTheme.text,
|
|
drawerStyle: {
|
|
backgroundColor: appContext.appTheme.drawer.backgroundColor,
|
|
},
|
|
}}
|
|
drawerContent={(props) => <SideBar {...props} />}
|
|
>
|
|
<Drawer.Screen
|
|
name="_noDevicesConnected"
|
|
component={NoDevicesConnectedStack}
|
|
/>
|
|
|
|
{appContext.devices.map((device) => (
|
|
<Drawer.Screen
|
|
key={device.id}
|
|
name={device.displayName}
|
|
component={DeviceScreenStack}
|
|
initialParams={{ deviceDisplayName: device.displayName }}
|
|
/>
|
|
))}
|
|
|
|
<Drawer.Screen name="Help" component={HelpScreenStack} />
|
|
<Drawer.Screen name="Settings" component={SettingsScreenStack} />
|
|
</Drawer.Navigator>
|
|
);
|
|
}
|
|
|
|
const DeviceScreenStack = (props) => {
|
|
return (
|
|
<MyScreenStack
|
|
name="device"
|
|
pageTitle={props.route.params.deviceDisplayName}
|
|
component={DeviceScreen}
|
|
navigation={props.navigation}
|
|
params={props.route.params}
|
|
/>
|
|
);
|
|
};
|
|
|
|
const NoDevicesConnectedStack = (props) => {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<MyScreenStack
|
|
name="noDevicesConnected"
|
|
pageTitle={t("screens.noDevicesConnected.pageTitle")}
|
|
component={NoDevicesConnectedScreen}
|
|
navigation={props.navigation}
|
|
/>
|
|
);
|
|
};
|
|
|
|
const HelpScreenStack = (props) => {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<MyScreenStack
|
|
name="help"
|
|
pageTitle={t("screens.help.pageTitle")}
|
|
component={HelpScreen}
|
|
navigation={props.navigation}
|
|
/>
|
|
);
|
|
};
|
|
|
|
const SettingsScreenStack = (props) => {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<MyScreenStack
|
|
name="settings"
|
|
pageTitle={t("screens.settings.pageTitle")}
|
|
component={SettingsScreen}
|
|
navigation={props.navigation}
|
|
/>
|
|
);
|
|
};
|
|
|
|
function getScreenStackOptions(
|
|
navigation,
|
|
pageTitle,
|
|
headerTintColor,
|
|
headerBackgroundColor,
|
|
isModalScreen
|
|
) {
|
|
return {
|
|
title: pageTitle,
|
|
headerLeft: () => (
|
|
<TouchableOpacity
|
|
onPress={() =>
|
|
isModalScreen ? navigation.goBack() : navigation.toggleDrawer()
|
|
}
|
|
>
|
|
<MyIcon
|
|
name={isModalScreen ? "chevron-left" : "menu"}
|
|
size={24}
|
|
style={[AppStyles.headerNavigationIcons]}
|
|
/>
|
|
</TouchableOpacity>
|
|
),
|
|
headerTintColor: headerTintColor,
|
|
headerTitleAlign: "center",
|
|
headerStyle: {
|
|
backgroundColor: headerBackgroundColor,
|
|
height: IsPlatformIos() ? 76 : 56,
|
|
},
|
|
};
|
|
}
|
|
|
|
function MyScreenStack({ navigation, name, pageTitle, component, params }) {
|
|
const appContext = useContext(AppContext);
|
|
|
|
return (
|
|
<Stack.Navigator initialRouteName={name}>
|
|
<Stack.Screen
|
|
name={name}
|
|
component={component}
|
|
initialParams={params}
|
|
options={getScreenStackOptions(
|
|
navigation,
|
|
pageTitle,
|
|
appContext.appTheme.text,
|
|
appContext.appTheme.backgroundColor
|
|
)}
|
|
/>
|
|
</Stack.Navigator>
|
|
);
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<Suspense
|
|
fallback={
|
|
<View
|
|
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
|
|
>
|
|
<Text>Loading...</Text>
|
|
</View>
|
|
}
|
|
>
|
|
<AppProvider>
|
|
<MyApp />
|
|
</AppProvider>
|
|
</Suspense>
|
|
);
|
|
}
|