From cf48bf0eafceee60324eaa14ab9ea1bfba1870c6 Mon Sep 17 00:00:00 2001 From: Douglas Lowder Date: Fri, 13 Oct 2023 11:52:45 -0700 Subject: [PATCH] Changes for TV support - New user pref "Show experimental features" (false by default) - New user prefs to hide/show different simulator types - Checkbox in settings for the experimental features - UI in menu bar dropdown to switch between different simulator lists - Awareness of osType=tvOS in common-types and eas-shared - Move .prettierrc.js to top of monorepo - Boolean user preferences are now always defined -- defaults in Storage.ts --- CHANGELOG.md | 1 + apps/menu-bar/.prettierrc.js | 7 -- apps/menu-bar/src/hooks/useListDevices.ts | 22 ++++++- apps/menu-bar/src/modules/Storage.ts | 22 +++++-- apps/menu-bar/src/popover/Core.tsx | 69 +++++++++++++++++++- apps/menu-bar/src/utils/device.ts | 5 +- apps/menu-bar/src/windows/Settings.tsx | 25 ++++++- packages/common-types/src/devices.ts | 2 +- packages/eas-shared/src/run/ios/simulator.ts | 6 +- 9 files changed, 138 insertions(+), 21 deletions(-) delete mode 100644 apps/menu-bar/.prettierrc.js diff --git a/CHANGELOG.md b/CHANGELOG.md index c078a48a..c533c6f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### 🎉 New features +- Add ability to show/hide different types of simulators, and add experimental TV support. ([#77](https://github.com/expo/orbit/pull/77) by [@douglowder](https://github.com/douglowder)) - Add support for opening tarballs with multiple apps. ([#73](https://github.com/expo/orbit/pull/73) by [@gabrieldonadel](https://github.com/gabrieldonadel)) - Improve feedback to the user when an error occurs. ([#64](https://github.com/expo/orbit/pull/64) by [@gabrieldonadel](https://github.com/gabrieldonadel)) - Added drag and drop support for installing apps. ([#57](https://github.com/expo/orbit/pull/57) by [@gabrieldonadel](https://github.com/gabrieldonadel)) diff --git a/apps/menu-bar/.prettierrc.js b/apps/menu-bar/.prettierrc.js deleted file mode 100644 index 51f103eb..00000000 --- a/apps/menu-bar/.prettierrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - printWidth: 100, - tabWidth: 2, - singleQuote: true, - bracketSameLine: true, - trailingComma: "es5", -} diff --git a/apps/menu-bar/src/hooks/useListDevices.ts b/apps/menu-bar/src/hooks/useListDevices.ts index e8ea93fe..2cb9882d 100644 --- a/apps/menu-bar/src/hooks/useListDevices.ts +++ b/apps/menu-bar/src/hooks/useListDevices.ts @@ -3,9 +3,10 @@ import { useCallback, useEffect, useState } from 'react'; import { DeviceEventEmitter } from 'react-native'; import { listDevicesAsync } from '../commands/listDevicesAsync'; +import { UserPreferences } from '../modules/Storage'; import { getSectionsFromDeviceList } from '../utils/device'; -export const useListDevices = () => { +export const useListDevices = (userPreferences: UserPreferences) => { const [devicesPerPlatform, setDevicesPerPlatform] = useState({ android: { devices: [] }, ios: { devices: [] }, @@ -19,13 +20,30 @@ export const useListDevices = () => { setLoading(true); try { const devicesList = await listDevicesAsync({ platform: 'all' }); + const showIos = userPreferences.showIosSimulators; + const showTvos = + userPreferences.showExperimentalFeatures && userPreferences.showTvosSimulators; + const showAndroid = userPreferences.showAndroidEmulators; + if (!showIos) { + devicesList.ios.devices = devicesList.ios.devices.filter( + (device) => device.osType !== 'iOS' + ); + } + if (!showTvos) { + devicesList.ios.devices = devicesList.ios.devices.filter( + (device) => device.osType !== 'tvOS' + ); + } + if (!showAndroid) { + devicesList.android.devices = []; + } setDevicesPerPlatform(devicesList); } catch (err) { setError(err as Error); } finally { setLoading(false); } - }, []); + }, [userPreferences]); useEffect(() => { const listener = DeviceEventEmitter.addListener('popoverFocused', () => { diff --git a/apps/menu-bar/src/modules/Storage.ts b/apps/menu-bar/src/modules/Storage.ts index dd49fb6c..56c6fabc 100644 --- a/apps/menu-bar/src/modules/Storage.ts +++ b/apps/menu-bar/src/modules/Storage.ts @@ -4,14 +4,28 @@ import { MMKV } from 'react-native-mmkv'; const userPreferencesStorageKey = 'user-preferences'; export type UserPreferences = { - launchOnLogin?: boolean; - emulatorWithoutAudio?: boolean; + launchOnLogin: boolean; + emulatorWithoutAudio: boolean; customSdkPath?: string; + showExperimentalFeatures: boolean; + showIosSimulators: boolean; + showTvosSimulators: boolean; + showAndroidEmulators: boolean; +}; + +export const defaultUserPreferences: UserPreferences = { + launchOnLogin: false, + emulatorWithoutAudio: false, + showExperimentalFeatures: false, + showIosSimulators: true, + showTvosSimulators: false, + showAndroidEmulators: true, }; export const getUserPreferences = async () => { - const value = await AsyncStorage.getItem(userPreferencesStorageKey); - return JSON.parse(value ?? '{}') as UserPreferences; + const stringValue = await AsyncStorage.getItem(userPreferencesStorageKey); + const value = (stringValue ? JSON.parse(stringValue) : defaultUserPreferences) as UserPreferences; + return value; }; export const saveUserPreferences = async (preferences: UserPreferences) => { diff --git a/apps/menu-bar/src/popover/Core.tsx b/apps/menu-bar/src/popover/Core.tsx index 232e5c14..4465cf8e 100644 --- a/apps/menu-bar/src/popover/Core.tsx +++ b/apps/menu-bar/src/popover/Core.tsx @@ -16,7 +16,7 @@ import { bootDeviceAsync } from '../commands/bootDeviceAsync'; import { downloadBuildAsync } from '../commands/downloadBuildAsync'; import { installAndLaunchAppAsync } from '../commands/installAndLaunchAppAsync'; import { launchSnackAsync } from '../commands/launchSnackAsync'; -import { Spacer, Text, View } from '../components'; +import { Checkbox, Spacer, Text, View } from '../components'; import DeviceItem, { DEVICE_ITEM_HEIGHT } from '../components/DeviceItem'; import ProgressIndicator from '../components/ProgressIndicator'; import { useDeepLinking } from '../hooks/useDeepLinking'; @@ -31,6 +31,10 @@ import { SelectedDevicesIds, getSelectedDevicesIds, saveSelectedDevicesIds, + UserPreferences, + defaultUserPreferences, + getUserPreferences, + saveUserPreferences, } from '../modules/Storage'; import { openProjectsSelectorURL } from '../utils/constants'; import { getDeviceId, getDeviceOS, isVirtualDevice } from '../utils/device'; @@ -54,6 +58,14 @@ function Core(props: Props) { android: undefined, ios: undefined, }); + const [userPreferences, setUserPreferences] = useState(defaultUserPreferences); + + useEffect(() => { + getUserPreferences().then((value) => { + saveUserPreferences(value); + setUserPreferences(value); + }); + }, []); const { apps } = useGetPinnedApps(); const showProjectsSection = Boolean(apps?.length); @@ -61,7 +73,8 @@ function Core(props: Props) { const [status, setStatus] = useState(Status.LISTENING); const [progress, setProgress] = useState(0); - const { devicesPerPlatform, numberOfDevices, sections, refetch } = useListDevices(); + const { devicesPerPlatform, numberOfDevices, sections, refetch } = + useListDevices(userPreferences); const { emulatorWithoutAudio } = useDeviceAudioPreferences(); const theme = useExpoTheme(); @@ -113,6 +126,36 @@ function Core(props: Props) { [emulatorWithoutAudio] ); + const onPressShowIosSimulators = async (value: boolean) => { + const newPreferences = { + ...userPreferences, + showIosSimulators: value, + }; + saveUserPreferences(newPreferences).then(() => { + setUserPreferences(newPreferences); + }); + }; + + const onPressShowTvosSimulators = async (value: boolean) => { + const newPreferences = { + ...userPreferences, + showTvosSimulators: value, + }; + saveUserPreferences(newPreferences).then(() => { + setUserPreferences(newPreferences); + }); + }; + + const onPressShowAndroidEmulators = async (value: boolean) => { + const newPreferences = { + ...userPreferences, + showAndroidEmulators: value, + }; + saveUserPreferences(newPreferences).then(() => { + setUserPreferences(newPreferences); + }); + }; + // @TODO: create another hook const handleSnackUrl = useCallback( async (url: string) => { @@ -277,6 +320,28 @@ function Core(props: Props) { ) : null} + + + Devices to show: + + + {userPreferences.showExperimentalFeatures ? ( + + ) : null} + + {apps?.length ? : null} { Boolean(storage.getString('sessionSecret')) ); - const [userPreferences, setUserPreferences] = useState({}); + const [userPreferences, setUserPreferences] = useState(defaultUserPreferences); const [customSdkPathEnabled, setCustomSdkPathEnabled] = useState(false); const [automaticallyChecksForUpdates, setAutomaticallyChecksForUpdates] = useState(false); @@ -78,6 +79,14 @@ const Settings = () => { SparkleModule.setAutomaticallyChecksForUpdates(value); }; + const onPressSetShowExperimentalFeatures = async (value: boolean) => { + setUserPreferences((prev) => { + const newPreferences = { ...prev, showExperimentalFeatures: value }; + saveUserPreferences(newPreferences); + return newPreferences; + }); + }; + const onPressEmulatorWithoutAudio = async (value: boolean) => { setUserPreferences((prev) => { const newPreferences = { ...prev, emulatorWithoutAudio: value }; @@ -167,6 +176,13 @@ const Settings = () => { color="primary" />