From 415e60614985090ca775c7ca44b42e574eda6bf6 Mon Sep 17 00:00:00 2001 From: filip131311 <159789821+filip131311@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:48:44 +0200 Subject: [PATCH] Fix small problems (#605) This PR fixes a few small problems: 1) it formats files added in #585 2) awaits isExpoGoProject in dependencyManager, before it was always false causing useDiagnosticAlert in expo go projects 3) adds new checks for android and ios native directories; before this change users that did not run `expo prebuild` were met with a generic build error alert that did not point them to the problem, now the information about the problem is added to the diagnostics panel, Radon IDE logs and a new message is added to build error alert to point user in the right direction Test plan: - run expo go project to test if IDE shows any unnecessary alerts - run non expo go application and remove android directory, then run android emulator and see the alerts that are shown by IDE --- .../src/builders/BuildManager.ts | 4 +- .../src/builders/buildAndroid.ts | 10 +- .../vscode-extension/src/builders/buildIOS.ts | 8 + .../src/common/DependencyManager.ts | 2 + .../src/dependency/DependencyManager.ts | 35 +- .../components/DeviceSettingsDropdown.css | 2 +- .../src/webview/components/DimensionsBox.tsx | 71 ++-- .../src/webview/components/Preview.tsx | 9 +- .../src/webview/components/ReplayUI.css | 385 +++++++++--------- .../src/webview/components/shared/Button.css | 2 +- .../src/webview/hooks/useBuildErrorAlert.tsx | 20 + .../providers/DependenciesProvider.tsx | 18 +- .../src/webview/views/DiagnosticView.tsx | 2 + 13 files changed, 339 insertions(+), 229 deletions(-) diff --git a/packages/vscode-extension/src/builders/BuildManager.ts b/packages/vscode-extension/src/builders/BuildManager.ts index ccb70c4d7..a56a24911 100644 --- a/packages/vscode-extension/src/builders/BuildManager.ts +++ b/packages/vscode-extension/src/builders/BuildManager.ts @@ -69,7 +69,8 @@ export class BuildManager { forceCleanBuild, cancelToken, this.buildOutputChannel, - progressListener + progressListener, + this.dependencyManager ); } else { this.buildOutputChannel = window.createOutputChannel("Radon IDE (iOS build)", { @@ -93,6 +94,7 @@ export class BuildManager { cancelToken, this.buildOutputChannel, progressListener, + this.dependencyManager, installPodsIfNeeded ); } diff --git a/packages/vscode-extension/src/builders/buildAndroid.ts b/packages/vscode-extension/src/builders/buildAndroid.ts index c51c8421a..0bb56711a 100644 --- a/packages/vscode-extension/src/builders/buildAndroid.ts +++ b/packages/vscode-extension/src/builders/buildAndroid.ts @@ -15,6 +15,7 @@ import { DevicePlatform } from "../common/DeviceManager"; import { getReactNativeVersion } from "../utilities/reactNative"; import { runExternalBuild } from "./customBuild"; import { fetchEasBuild } from "./eas"; +import { DependencyManager } from "../dependency/DependencyManager"; export type AndroidBuildResult = { platform: DevicePlatform.Android; @@ -76,7 +77,8 @@ export async function buildAndroid( forceCleanBuild: boolean, cancelToken: CancelToken, outputChannel: OutputChannel, - progressListener: (newProgress: number) => void + progressListener: (newProgress: number) => void, + dependencyManager: DependencyManager ): Promise { const { customBuild, eas, env, android } = getLaunchConfiguration(); @@ -117,6 +119,12 @@ export async function buildAndroid( return { apkPath, packageName: EXPO_GO_PACKAGE_NAME, platform: DevicePlatform.Android }; } + if (!(await dependencyManager.isInstalled("android"))) { + throw new Error( + "Android directory does not exist, configure build source in launch configuration or use expo prebuild to generate the directory" + ); + } + const androidSourceDir = getAndroidSourceDir(appRootFolder); const productFlavor = android?.productFlavor || ""; const buildType = android?.buildType || "debug"; diff --git a/packages/vscode-extension/src/builders/buildIOS.ts b/packages/vscode-extension/src/builders/buildIOS.ts index 02ad30ebc..bb8bd21ea 100644 --- a/packages/vscode-extension/src/builders/buildIOS.ts +++ b/packages/vscode-extension/src/builders/buildIOS.ts @@ -11,6 +11,7 @@ import { findXcodeProject, findXcodeScheme, IOSProjectInfo } from "../utilities/ import { runExternalBuild } from "./customBuild"; import { fetchEasBuild } from "./eas"; import { getXcodebuildArch } from "../utilities/common"; +import { DependencyManager } from "../dependency/DependencyManager"; export type IOSBuildResult = { platform: DevicePlatform.IOS; @@ -76,6 +77,7 @@ export async function buildIos( cancelToken: CancelToken, outputChannel: OutputChannel, progressListener: (newProgress: number) => void, + dependencyManager: DependencyManager, installPodsIfNeeded: () => Promise ): Promise { const { customBuild, eas, ios: buildOptions, env } = getLaunchConfiguration(); @@ -119,6 +121,12 @@ export async function buildIos( return { appPath, bundleID: EXPO_GO_BUNDLE_ID, platform: DevicePlatform.IOS }; } + if (!(await dependencyManager.isInstalled("ios"))) { + throw new Error( + "Ios directory does not exist, configure build source in launch configuration or use expo prebuild to generate the directory" + ); + } + const sourceDir = getIosSourceDir(appRootFolder); await installPodsIfNeeded(); diff --git a/packages/vscode-extension/src/common/DependencyManager.ts b/packages/vscode-extension/src/common/DependencyManager.ts index 63e51f042..155081f71 100644 --- a/packages/vscode-extension/src/common/DependencyManager.ts +++ b/packages/vscode-extension/src/common/DependencyManager.ts @@ -12,6 +12,8 @@ export type Dependency = | "cocoaPods" | "nodejs" | "nodeModules" + | "android" + | "ios" | "pods" | "reactNative" | "expo" diff --git a/packages/vscode-extension/src/dependency/DependencyManager.ts b/packages/vscode-extension/src/dependency/DependencyManager.ts index e0be4b475..361987edb 100644 --- a/packages/vscode-extension/src/dependency/DependencyManager.ts +++ b/packages/vscode-extension/src/dependency/DependencyManager.ts @@ -27,6 +27,7 @@ import { } from "../common/DependencyManager"; import { shouldUseExpoCLI } from "../utilities/expoCli"; import { CancelToken } from "../builders/cancelToken"; +import { getAndroidSourceDir } from "../builders/buildAndroid"; const STALE_PODS = "stalePods"; @@ -67,11 +68,19 @@ export class DependencyManager implements Disposable, DependencyManagerInterface case "nodeModules": return { status: await this.nodeModulesStatus(), isOptional: false }; case "pods": - return { status: await this.podsStatus(), isOptional: !isExpoGoProject() }; + return { status: await this.podsStatus(), isOptional: await isExpoGoProject() }; case "reactNative": { const status = dependencyStatus("react-native", MinSupportedVersion.reactNative); return { status, isOptional: false }; } + case "android": { + const status = this.androidDirectoryExits() ? "installed" : "notInstalled"; + return { status, isOptional: await areNativeDirectoriesOptional() }; + } + case "ios": { + const status = this.iosDirectoryExits() ? "installed" : "notInstalled"; + return { status, isOptional: await areNativeDirectoriesOptional() }; + } case "expo": { const status = dependencyStatus("expo", MinSupportedVersion.expo); return { status, isOptional: !shouldUseExpoCLI() }; @@ -98,6 +107,24 @@ export class DependencyManager implements Disposable, DependencyManagerInterface return diagnostics; } + androidDirectoryExits() { + const appRootFolder = getAppRootFolder(); + const androidDirPath = getAndroidSourceDir(appRootFolder); + if (fs.existsSync(androidDirPath)) { + return true; + } + return false; + } + + iosDirectoryExits() { + const appRootFolder = getAppRootFolder(); + const iosDirPath = getIosSourceDir(appRootFolder); + if (fs.existsSync(iosDirPath)) { + return true; + } + return false; + } + public async isInstalled(dependency: Dependency) { const status = await this.getStatus([dependency]); return status[dependency].status === "installed"; @@ -321,3 +348,9 @@ function isUsingExpoRouter() { return false; } } +async function areNativeDirectoriesOptional(): Promise { + const isExpoGo = await isExpoGoProject(); + const launchConfiguration = getLaunchConfiguration(); + + return isExpoGo && !!launchConfiguration.eas && !!launchConfiguration.customBuild; +} diff --git a/packages/vscode-extension/src/webview/components/DeviceSettingsDropdown.css b/packages/vscode-extension/src/webview/components/DeviceSettingsDropdown.css index 297b2837a..4f8cae67f 100644 --- a/packages/vscode-extension/src/webview/components/DeviceSettingsDropdown.css +++ b/packages/vscode-extension/src/webview/components/DeviceSettingsDropdown.css @@ -41,4 +41,4 @@ .icons-container { display: flex; align-items: center; -} \ No newline at end of file +} diff --git a/packages/vscode-extension/src/webview/components/DimensionsBox.tsx b/packages/vscode-extension/src/webview/components/DimensionsBox.tsx index 71515a78a..0c0736589 100644 --- a/packages/vscode-extension/src/webview/components/DimensionsBox.tsx +++ b/packages/vscode-extension/src/webview/components/DimensionsBox.tsx @@ -20,9 +20,9 @@ type DimensionsBoxProps = { wrapperDivRef: React.RefObject; }; -type DimensionsBoxPosition = 'above' | 'below' | 'left' | 'right' | 'inside'; +type DimensionsBoxPosition = "above" | "below" | "left" | "right" | "inside"; -function DimensionsBox({ device, frame, wrapperDivRef } : DimensionsBoxProps) { +function DimensionsBox({ device, frame, wrapperDivRef }: DimensionsBoxProps) { if (!device) { return; } @@ -32,9 +32,11 @@ function DimensionsBox({ device, frame, wrapperDivRef } : DimensionsBoxProps) { const previewDiv = wrapperDivRef.current?.childNodes?.[0] as unknown; - if (!previewDiv || typeof previewDiv !== 'object' - || !('clientHeight' in previewDiv) - || typeof previewDiv.clientHeight !== 'number' + if ( + !previewDiv || + typeof previewDiv !== "object" || + !("clientHeight" in previewDiv) || + typeof previewDiv.clientHeight !== "number" ) { return; } @@ -42,45 +44,50 @@ function DimensionsBox({ device, frame, wrapperDivRef } : DimensionsBoxProps) { const { clientHeight: previewHeight } = previewDiv; const boxPosition: DimensionsBoxPosition = (() => { - if (frame.y >= VERTICAL_POSITION_THRESHOLD) {return 'above';} - else if (frame.y + frame.height <= 1 - VERTICAL_POSITION_THRESHOLD) {return 'below';} - else if (frame.x + frame.width <= HORIZONTAL_POSITION_THRESHOLD) {return 'right';} - else if (frame.x >= 1 - HORIZONTAL_POSITION_THRESHOLD) {return 'left';} - return 'inside'; + if (frame.y >= VERTICAL_POSITION_THRESHOLD) { + return "above"; + } else if (frame.y + frame.height <= 1 - VERTICAL_POSITION_THRESHOLD) { + return "below"; + } else if (frame.x + frame.width <= HORIZONTAL_POSITION_THRESHOLD) { + return "right"; + } else if (frame.x >= 1 - HORIZONTAL_POSITION_THRESHOLD) { + return "left"; + } + return "inside"; })(); const positionalProps = (() => { switch (boxPosition) { - case 'above': + case "above": return { "--top": `${(frame.y - VERTICAL_ARROW_MARGIN) * 100}%`, - "--left": `${(frame.x + frame.width/2) * 100}%`, - "--box-transform": 'translate(-50%, -100%)' + "--left": `${(frame.x + frame.width / 2) * 100}%`, + "--box-transform": "translate(-50%, -100%)", }; - case 'below': + case "below": return { "--top": `${(frame.y + frame.height + VERTICAL_ARROW_MARGIN) * 100}%`, - "--left": `${(frame.x + frame.width/2) * 100}%`, - "--box-transform": 'translate(-50%, 0%)' + "--left": `${(frame.x + frame.width / 2) * 100}%`, + "--box-transform": "translate(-50%, 0%)", }; - case 'right': + case "right": return { - "--top": `${(frame.y + frame.height/2) * 100}%`, + "--top": `${(frame.y + frame.height / 2) * 100}%`, "--left": `${(frame.x + frame.width + HORIZONTAL_ARROW_MARGIN) * 100}%`, - "--box-transform": 'translate(0%, -50%)' + "--box-transform": "translate(0%, -50%)", }; - case 'left': + case "left": return { - "--top": `${(frame.y + frame.height/2) * 100}%`, + "--top": `${(frame.y + frame.height / 2) * 100}%`, "--left": `${(frame.x - HORIZONTAL_ARROW_MARGIN) * 100}%`, - "--box-transform": 'translate(-100%, -50%)' + "--box-transform": "translate(-100%, -50%)", }; - default: + default: return { - "--top": `${(frame.y + frame.height/2) * 100}%`, - "--left": `${(frame.x + frame.width/2) * 100}%`, - "--box-transform": 'translate(-50%, -50%)' - }; + "--top": `${(frame.y + frame.height / 2) * 100}%`, + "--left": `${(frame.x + frame.width / 2) * 100}%`, + "--box-transform": "translate(-50%, -50%)", + }; } })(); @@ -92,17 +99,17 @@ function DimensionsBox({ device, frame, wrapperDivRef } : DimensionsBoxProps) { "--border-radius": `${boxHeight * BORDER_RADIUS_FRACTION}px`, "--horizontal-padding": `${boxHeight * HORIZONTAL_PADDING_FRACTION}px`, "--arrow-size": `${boxHeight * ARROW_SIZE_FRACTION}px`, - ...positionalProps + ...positionalProps, }; return (
- { boxPosition !== 'inside' &&
} + {boxPosition !== "inside" &&
}
- { width } × { height } -
+ {width} × {height} +
); -}; +} export default DimensionsBox; diff --git a/packages/vscode-extension/src/webview/components/Preview.tsx b/packages/vscode-extension/src/webview/components/Preview.tsx index 656ff2753..2896444f2 100644 --- a/packages/vscode-extension/src/webview/components/Preview.tsx +++ b/packages/vscode-extension/src/webview/components/Preview.tsx @@ -14,12 +14,7 @@ import PreviewLoader from "./PreviewLoader"; import { useBuildErrorAlert, useBundleErrorAlert } from "../hooks/useBuildErrorAlert"; import Debugger from "./Debugger"; import { useNativeRebuildAlert } from "../hooks/useNativeRebuildAlert"; -import { - Frame, - InspectDataStackItem, - RecordingData, - ZoomLevelType, -} from "../../common/Project"; +import { Frame, InspectDataStackItem, RecordingData, ZoomLevelType } from "../../common/Project"; import { InspectDataMenu } from "./InspectDataMenu"; import { useResizableProps } from "../hooks/useResizableProps"; import ZoomControls from "./ZoomControls"; @@ -589,7 +584,7 @@ function Preview({ />
diff --git a/packages/vscode-extension/src/webview/components/ReplayUI.css b/packages/vscode-extension/src/webview/components/ReplayUI.css index fd46a8c85..3e9356bd3 100644 --- a/packages/vscode-extension/src/webview/components/ReplayUI.css +++ b/packages/vscode-extension/src/webview/components/ReplayUI.css @@ -1,230 +1,247 @@ .vhs-noise { - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - overflow: hidden; - z-index: 400; - opacity: 0.8; - pointer-events: none; - opacity: 1; - z-index: 450; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + overflow: hidden; + z-index: 400; + opacity: 0.8; + pointer-events: none; + opacity: 1; + z-index: 450; } .vhs-noise:before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - /* small bitmap displaying a white noise */ - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAUVBMVEWFhYWDg4N3d3dtbW17e3t1dXWBgYGHh4d5eXlzc3OLi4ubm5uVlZWPj4+NjY19fX2JiYl/f39ra2uRkZGZmZlpaWmXl5dvb29xcXGTk5NnZ2c8TV1mAAAAG3RSTlNAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAvEOwtAAAFVklEQVR4XpWWB67c2BUFb3g557T/hRo9/WUMZHlgr4Bg8Z4qQgQJlHI4A8SzFVrapvmTF9O7dmYRFZ60YiBhJRCgh1FYhiLAmdvX0CzTOpNE77ME0Zty/nWWzchDtiqrmQDeuv3powQ5ta2eN0FY0InkqDD73lT9c9lEzwUNqgFHs9VQce3TVClFCQrSTfOiYkVJQBmpbq2L6iZavPnAPcoU0dSw0SUTqz/GtrGuXfbyyBniKykOWQWGqwwMA7QiYAxi+IlPdqo+hYHnUt5ZPfnsHJyNiDtnpJyayNBkF6cWoYGAMY92U2hXHF/C1M8uP/ZtYdiuj26UdAdQQSXQErwSOMzt/XWRWAz5GuSBIkwG1H3FabJ2OsUOUhGC6tK4EMtJO0ttC6IBD3kM0ve0tJwMdSfjZo+EEISaeTr9P3wYrGjXqyC1krcKdhMpxEnt5JetoulscpyzhXN5FRpuPHvbeQaKxFAEB6EN+cYN6xD7RYGpXpNndMmZgM5Dcs3YSNFDHUo2LGfZuukSWyUYirJAdYbF3MfqEKmjM+I2EfhA94iG3L7uKrR+GdWD73ydlIB+6hgref1QTlmgmbM3/LeX5GI1Ux1RWpgxpLuZ2+I+IjzZ8wqE4nilvQdkUdfhzI5QDWy+kw5Wgg2pGpeEVeCCA7b85BO3F9DzxB3cdqvBzWcmzbyMiqhzuYqtHRVG2y4x+KOlnyqla8AoWWpuBoYRxzXrfKuILl6SfiWCbjxoZJUaCBj1CjH7GIaDbc9kqBY3W/Rgjda1iqQcOJu2WW+76pZC9QG7M00dffe9hNnseupFL53r8F7YHSwJWUKP2q+k7RdsxyOB11n0xtOvnW4irMMFNV4H0uqwS5ExsmP9AxbDTc9JwgneAT5vTiUSm1E7BSflSt3bfa1tv8Di3R8n3Af7MNWzs49hmauE2wP+ttrq+AsWpFG2awvsuOqbipWHgtuvuaAE+A1Z/7gC9hesnr+7wqCwG8c5yAg3AL1fm8T9AZtp/bbJGwl1pNrE7RuOX7PeMRUERVaPpEs+yqeoSmuOlokqw49pgomjLeh7icHNlG19yjs6XXOMedYm5xH2YxpV2tc0Ro2jJfxC50ApuxGob7lMsxfTbeUv07TyYxpeLucEH1gNd4IKH2LAg5TdVhlCafZvpskfncCfx8pOhJzd76bJWeYFnFciwcYfubRc12Ip/ppIhA1/mSZ/RxjFDrJC5xifFjJpY2Xl5zXdguFqYyTR1zSp1Y9p+tktDYYSNflcxI0iyO4TPBdlRcpeqjK/piF5bklq77VSEaA+z8qmJTFzIWiitbnzR794USKBUaT0NTEsVjZqLaFVqJoPN9ODG70IPbfBHKK+/q/AWR0tJzYHRULOa4MP+W/HfGadZUbfw177G7j/OGbIs8TahLyynl4X4RinF793Oz+BU0saXtUHrVBFT/DnA3ctNPoGbs4hRIjTok8i+algT1lTHi4SxFvONKNrgQFAq2/gFnWMXgwffgYMJpiKYkmW3tTg3ZQ9Jq+f8XN+A5eeUKHWvJWJ2sgJ1Sop+wwhqFVijqWaJhwtD8MNlSBeWNNWTa5Z5kPZw5+LbVT99wqTdx29lMUH4OIG/D86ruKEauBjvH5xy6um/Sfj7ei6UUVk4AIl3MyD4MSSTOFgSwsH/QJWaQ5as7ZcmgBZkzjjU1UrQ74ci1gWBCSGHtuV1H2mhSnO3Wp/3fEV5a+4wz//6qy8JxjZsmxxy5+4w9CDNJY09T072iKG0EnOS0arEYgXqYnXcYHwjTtUNAcMelOd4xpkoqiTYICWFq0JSiPfPDQdnt+4/wuqcXY47QILbgAAAABJRU5ErkJggg==); - pointer-events: none; - will-change: background-position; - animation: noise 1s infinite alternate; + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + /* small bitmap displaying a white noise */ + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAUVBMVEWFhYWDg4N3d3dtbW17e3t1dXWBgYGHh4d5eXlzc3OLi4ubm5uVlZWPj4+NjY19fX2JiYl/f39ra2uRkZGZmZlpaWmXl5dvb29xcXGTk5NnZ2c8TV1mAAAAG3RSTlNAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAvEOwtAAAFVklEQVR4XpWWB67c2BUFb3g557T/hRo9/WUMZHlgr4Bg8Z4qQgQJlHI4A8SzFVrapvmTF9O7dmYRFZ60YiBhJRCgh1FYhiLAmdvX0CzTOpNE77ME0Zty/nWWzchDtiqrmQDeuv3powQ5ta2eN0FY0InkqDD73lT9c9lEzwUNqgFHs9VQce3TVClFCQrSTfOiYkVJQBmpbq2L6iZavPnAPcoU0dSw0SUTqz/GtrGuXfbyyBniKykOWQWGqwwMA7QiYAxi+IlPdqo+hYHnUt5ZPfnsHJyNiDtnpJyayNBkF6cWoYGAMY92U2hXHF/C1M8uP/ZtYdiuj26UdAdQQSXQErwSOMzt/XWRWAz5GuSBIkwG1H3FabJ2OsUOUhGC6tK4EMtJO0ttC6IBD3kM0ve0tJwMdSfjZo+EEISaeTr9P3wYrGjXqyC1krcKdhMpxEnt5JetoulscpyzhXN5FRpuPHvbeQaKxFAEB6EN+cYN6xD7RYGpXpNndMmZgM5Dcs3YSNFDHUo2LGfZuukSWyUYirJAdYbF3MfqEKmjM+I2EfhA94iG3L7uKrR+GdWD73ydlIB+6hgref1QTlmgmbM3/LeX5GI1Ux1RWpgxpLuZ2+I+IjzZ8wqE4nilvQdkUdfhzI5QDWy+kw5Wgg2pGpeEVeCCA7b85BO3F9DzxB3cdqvBzWcmzbyMiqhzuYqtHRVG2y4x+KOlnyqla8AoWWpuBoYRxzXrfKuILl6SfiWCbjxoZJUaCBj1CjH7GIaDbc9kqBY3W/Rgjda1iqQcOJu2WW+76pZC9QG7M00dffe9hNnseupFL53r8F7YHSwJWUKP2q+k7RdsxyOB11n0xtOvnW4irMMFNV4H0uqwS5ExsmP9AxbDTc9JwgneAT5vTiUSm1E7BSflSt3bfa1tv8Di3R8n3Af7MNWzs49hmauE2wP+ttrq+AsWpFG2awvsuOqbipWHgtuvuaAE+A1Z/7gC9hesnr+7wqCwG8c5yAg3AL1fm8T9AZtp/bbJGwl1pNrE7RuOX7PeMRUERVaPpEs+yqeoSmuOlokqw49pgomjLeh7icHNlG19yjs6XXOMedYm5xH2YxpV2tc0Ro2jJfxC50ApuxGob7lMsxfTbeUv07TyYxpeLucEH1gNd4IKH2LAg5TdVhlCafZvpskfncCfx8pOhJzd76bJWeYFnFciwcYfubRc12Ip/ppIhA1/mSZ/RxjFDrJC5xifFjJpY2Xl5zXdguFqYyTR1zSp1Y9p+tktDYYSNflcxI0iyO4TPBdlRcpeqjK/piF5bklq77VSEaA+z8qmJTFzIWiitbnzR794USKBUaT0NTEsVjZqLaFVqJoPN9ODG70IPbfBHKK+/q/AWR0tJzYHRULOa4MP+W/HfGadZUbfw177G7j/OGbIs8TahLyynl4X4RinF793Oz+BU0saXtUHrVBFT/DnA3ctNPoGbs4hRIjTok8i+algT1lTHi4SxFvONKNrgQFAq2/gFnWMXgwffgYMJpiKYkmW3tTg3ZQ9Jq+f8XN+A5eeUKHWvJWJ2sgJ1Sop+wwhqFVijqWaJhwtD8MNlSBeWNNWTa5Z5kPZw5+LbVT99wqTdx29lMUH4OIG/D86ruKEauBjvH5xy6um/Sfj7ei6UUVk4AIl3MyD4MSSTOFgSwsH/QJWaQ5as7ZcmgBZkzjjU1UrQ74ci1gWBCSGHtuV1H2mhSnO3Wp/3fEV5a+4wz//6qy8JxjZsmxxy5+4w9CDNJY09T072iKG0EnOS0arEYgXqYnXcYHwjTtUNAcMelOd4xpkoqiTYICWFq0JSiPfPDQdnt+4/wuqcXY47QILbgAAAABJRU5ErkJggg==); + pointer-events: none; + will-change: background-position; + animation: noise 1s infinite alternate; } .crt-lines { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-image: linear-gradient(30deg, - rgba(17, 20, 53, 0.3), - rgba(118, 255, 241, 0.3)); - background-repeat: repeat; - background-size: 100% 10%; - animation: bgscroll 2s linear infinite; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-image: linear-gradient(30deg, rgba(17, 20, 53, 0.3), rgba(118, 255, 241, 0.3)); + background-repeat: repeat; + background-size: 100% 10%; + animation: bgscroll 2s linear infinite; } .vhs-lines { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: 300; - opacity: 0.5; - will-change: opacity; - animation: opacity 3s linear infinite; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 300; + opacity: 0.5; + will-change: opacity; + animation: opacity 3s linear infinite; } .vhs-lines:before { - content: ''; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - pointer-events: none; - background: linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, .5) 51%); - background-size: 100% 4px; - will-change: background, background-size; - animation: scanlines 0.2s linear infinite; + content: ""; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + pointer-events: none; + background: linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, 0.5) 51%); + background-size: 100% 4px; + will-change: background, background-size; + animation: scanlines 0.2s linear infinite; } .vhs-bg { - position: absolute; - top: 0; - left: 0; - color: #fff; - font-size: 2rem; - width: 100%; - height: 100%; - background: grey; - opacity: 0.5; + position: absolute; + top: 0; + left: 0; + color: #fff; + font-size: 2rem; + width: 100%; + height: 100%; + background: grey; + opacity: 0.5; } .vhs-bg .vhs-noise:before { - background-size: 150%; + background-size: 150%; } .vhs-text { - position: absolute; - overflow: hidden; - right: 10%; - top: 15%; - will-change: text-shadow; - filter: blur(1px); - font-family: 'Courier new', fixed; - animation: rgbText 1s steps(9) 0s infinite alternate; + position: absolute; + overflow: hidden; + right: 10%; + top: 15%; + will-change: text-shadow; + filter: blur(1px); + font-family: "Courier new", fixed; + animation: rgbText 1s steps(9) 0s infinite alternate; } @keyframes noise { - - 0%, - 100% { - background-position: 0 0; - } - - 10% { - background-position: -5% -10%; - } - - 20% { - background-position: -15% 5%; - } - - 30% { - background-position: 7% -25%; - } - - 40% { - background-position: 20% 25%; - } - - 50% { - background-position: -25% 10%; - } - - 60% { - background-position: 15% 5%; - } - - 70% { - background-position: 0 15%; - } - - 80% { - background-position: 25% 35%; - } - - 90% { - background-position: -10% 10%; - } + 0%, + 100% { + background-position: 0 0; + } + + 10% { + background-position: -5% -10%; + } + + 20% { + background-position: -15% 5%; + } + + 30% { + background-position: 7% -25%; + } + + 40% { + background-position: 20% 25%; + } + + 50% { + background-position: -25% 10%; + } + + 60% { + background-position: 15% 5%; + } + + 70% { + background-position: 0 15%; + } + + 80% { + background-position: 25% 35%; + } + + 90% { + background-position: -10% 10%; + } } @keyframes opacity { - 0% { - opacity: 0.6; - } + 0% { + opacity: 0.6; + } - 20% { - opacity: 0.3; - } + 20% { + opacity: 0.3; + } - 35% { - opacity: 0.5; - } + 35% { + opacity: 0.5; + } - 50% { - opacity: 0.8; - } + 50% { + opacity: 0.8; + } - 60% { - opacity: 0.4; - } + 60% { + opacity: 0.4; + } - 80% { - opacity: 0.7; - } + 80% { + opacity: 0.7; + } - 100% { - opacity: 0.6; - } + 100% { + opacity: 0.6; + } } @keyframes bgscroll { - 100% { - background-position: 0% 100%; - } + 100% { + background-position: 0% 100%; + } } @keyframes scanlines { - from { - background: linear-gradient(-30deg, to bottom, transparent 80%, rgba(0, 0, 0, .5) 51%); - background-size: 100% 10%; - } - - to { - background: linear-gradient(-30deg, to bottom, rgba(0, 0, 0, .5) 50%, transparent 51%); - background-size: 100% 5%; - } + from { + background: linear-gradient(-30deg, to bottom, transparent 80%, rgba(0, 0, 0, 0.5) 51%); + background-size: 100% 10%; + } + + to { + background: linear-gradient(-30deg, to bottom, rgba(0, 0, 0, 0.5) 50%, transparent 51%); + background-size: 100% 5%; + } } @keyframes rgbText { - 0% { - text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), 0px 0 1px rgba(251, 0, 231, 0.8), 0 0px 3px rgba(0, 233, 235, 0.8), 0px 0 3px rgba(0, 242, 14, 0.8), 0 0px 3px rgba(244, 45, 0, 0.8), 0px 0 3px rgba(59, 0, 226, 0.8); - } - - 25% { - text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), 0px 0 1px rgba(251, 0, 231, 0.8), 0 0px 3px rgba(0, 233, 235, 0.8), 0px 0 3px rgba(0, 242, 14, 0.8), 0 0px 3px rgba(244, 45, 0, 0.8), 0px 0 3px rgba(59, 0, 226, 0.8); - } - - 45% { - text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), 5px 0 1px rgba(251, 0, 231, 0.8), 0 5px 1px rgba(0, 233, 235, 0.8), -5px 0 1px rgba(0, 242, 14, 0.8), 0 -5px 1px rgba(244, 45, 0, 0.8), 5px 0 1px rgba(59, 0, 226, 0.8); - } - - 50% { - text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), -5px 0 1px rgba(251, 0, 231, 0.8), 0 -5px 1px rgba(0, 233, 235, 0.8), 5px 0 1px rgba(0, 242, 14, 0.8), 0 5px 1px rgba(244, 45, 0, 0.8), -5px 0 1px rgba(59, 0, 226, 0.8); - } - - 55% { - text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), 0px 0 3px rgba(251, 0, 231, 0.8), 0 0px 3px rgba(0, 233, 235, 0.8), 0px 0 3px rgba(0, 242, 14, 0.8), 0 0px 3px rgba(244, 45, 0, 0.8), 0px 0 3px rgba(59, 0, 226, 0.8); - } - - 90% { - text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), -5px 0 1px rgba(251, 0, 231, 0.8), 0 5px 1px rgba(0, 233, 235, 0.8), 5px 0 1px rgba(0, 242, 14, 0.8), 0 -5px 1px rgba(244, 45, 0, 0.8), 5px 0 1px rgba(59, 0, 226, 0.8); - } - - 100% { - text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), 5px 0 1px rgba(251, 0, 231, 0.8), 0 -5px 1px rgba(0, 233, 235, 0.8), -5px 0 1px rgba(0, 242, 14, 0.8), 0 5px 1px rgba(244, 45, 0, 0.8), -5px 0 1px rgba(59, 0, 226, 0.8); - } + 0% { + text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), + 0px 0 1px rgba(251, 0, 231, 0.8), 0 0px 3px rgba(0, 233, 235, 0.8), + 0px 0 3px rgba(0, 242, 14, 0.8), 0 0px 3px rgba(244, 45, 0, 0.8), + 0px 0 3px rgba(59, 0, 226, 0.8); + } + + 25% { + text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), + 0px 0 1px rgba(251, 0, 231, 0.8), 0 0px 3px rgba(0, 233, 235, 0.8), + 0px 0 3px rgba(0, 242, 14, 0.8), 0 0px 3px rgba(244, 45, 0, 0.8), + 0px 0 3px rgba(59, 0, 226, 0.8); + } + + 45% { + text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), + 5px 0 1px rgba(251, 0, 231, 0.8), 0 5px 1px rgba(0, 233, 235, 0.8), + -5px 0 1px rgba(0, 242, 14, 0.8), 0 -5px 1px rgba(244, 45, 0, 0.8), + 5px 0 1px rgba(59, 0, 226, 0.8); + } + + 50% { + text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), + -5px 0 1px rgba(251, 0, 231, 0.8), 0 -5px 1px rgba(0, 233, 235, 0.8), + 5px 0 1px rgba(0, 242, 14, 0.8), 0 5px 1px rgba(244, 45, 0, 0.8), + -5px 0 1px rgba(59, 0, 226, 0.8); + } + + 55% { + text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), + 0px 0 3px rgba(251, 0, 231, 0.8), 0 0px 3px rgba(0, 233, 235, 0.8), + 0px 0 3px rgba(0, 242, 14, 0.8), 0 0px 3px rgba(244, 45, 0, 0.8), + 0px 0 3px rgba(59, 0, 226, 0.8); + } + + 90% { + text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), + -5px 0 1px rgba(251, 0, 231, 0.8), 0 5px 1px rgba(0, 233, 235, 0.8), + 5px 0 1px rgba(0, 242, 14, 0.8), 0 -5px 1px rgba(244, 45, 0, 0.8), + 5px 0 1px rgba(59, 0, 226, 0.8); + } + + 100% { + text-shadow: -1px 1px 8px rgba(255, 255, 255, 0.6), 1px -1px 8px rgba(255, 255, 235, 0.7), + 5px 0 1px rgba(251, 0, 231, 0.8), 0 -5px 1px rgba(0, 233, 235, 0.8), + -5px 0 1px rgba(0, 242, 14, 0.8), 0 5px 1px rgba(244, 45, 0, 0.8), + -5px 0 1px rgba(59, 0, 226, 0.8); + } } @keyframes type { - - 0%, - 19% { - opacity: 0; - } - - 20%, - 100% { - opacity: 1; - } -} \ No newline at end of file + 0%, + 19% { + opacity: 0; + } + + 20%, + 100% { + opacity: 1; + } +} diff --git a/packages/vscode-extension/src/webview/components/shared/Button.css b/packages/vscode-extension/src/webview/components/shared/Button.css index df05db284..f82c57daf 100644 --- a/packages/vscode-extension/src/webview/components/shared/Button.css +++ b/packages/vscode-extension/src/webview/components/shared/Button.css @@ -81,4 +81,4 @@ .button-replay:hover { background-color: var(--swm-button-replay-hover); -} \ No newline at end of file +} diff --git a/packages/vscode-extension/src/webview/hooks/useBuildErrorAlert.tsx b/packages/vscode-extension/src/webview/hooks/useBuildErrorAlert.tsx index 1cf4f4472..446fc8536 100644 --- a/packages/vscode-extension/src/webview/hooks/useBuildErrorAlert.tsx +++ b/packages/vscode-extension/src/webview/hooks/useBuildErrorAlert.tsx @@ -5,6 +5,8 @@ import IconButton from "../components/shared/IconButton"; import { useModal } from "../providers/ModalProvider"; import LaunchConfigurationView from "../views/LaunchConfigurationView"; import { useLaunchConfig } from "../providers/LaunchConfigProvider"; +import { useDependencies } from "../providers/DependenciesProvider"; +import { DevicePlatform } from "../../common/DeviceManager"; function BuildErrorActions() { const { project } = useProject(); @@ -41,6 +43,8 @@ function BuildErrorActions() { export function useBuildErrorAlert(shouldDisplayAlert: boolean) { const { ios, xcodeSchemes } = useLaunchConfig(); + const { dependencies } = useDependencies(); + const { projectState } = useProject(); let description = "Open build logs to find out what went wrong."; @@ -48,6 +52,22 @@ export function useBuildErrorAlert(shouldDisplayAlert: boolean) { description = `Your project uses multiple build schemas. Currently used scheme: '${xcodeSchemes[0]}'. You can change it in the launch configuration.`; } + if ( + dependencies.android?.status === "notInstalled" && + projectState.selectedDevice?.platform === DevicePlatform.Android + ) { + description = + "Your project does not have an android directory, configure custom build source, eas or use expo prebuild to generate missing files."; + } + + if ( + dependencies.ios?.status === "notInstalled" && + projectState.selectedDevice?.platform === DevicePlatform.IOS + ) { + description = + "Your project does not have an ios directory, configure custom build source, eas or use expo prebuild to generate missing files."; + } + const buildErrorAlert = { id: "build-error-alert", title: "Cannot run project", diff --git a/packages/vscode-extension/src/webview/providers/DependenciesProvider.tsx b/packages/vscode-extension/src/webview/providers/DependenciesProvider.tsx index 615321530..278891d21 100644 --- a/packages/vscode-extension/src/webview/providers/DependenciesProvider.tsx +++ b/packages/vscode-extension/src/webview/providers/DependenciesProvider.tsx @@ -23,6 +23,8 @@ const dependencies = [ "xcode", "cocoaPods", "nodeModules", + "ios", + "android", "pods", "reactNative", "expo", @@ -138,7 +140,7 @@ function getErrors(statuses: Record) { hasErrors = true; if (!errors[errorName]) { const message = dependencyDescription(dependency).error; - errors.simulator = { message }; + errors[errorName] = { message }; } } @@ -164,6 +166,10 @@ function getErrors(statuses: Record) { case "nodeModules": setFirstError(dependency, "common"); break; + case "ios": + setFirstError(dependency, "ios"); + case "android": + setFirstError(dependency, "android"); default: break; } @@ -217,6 +223,16 @@ export function dependencyDescription(dependency: Dependency) { info: "Whether supported version of React Native is installed.", error: `React Native is not installed or it is older than supported version ${MinSupportedVersion.reactNative}.`, }; + case "ios": + return { + info: "Whether ios directory exists in the project", + error: "Ios directory does not exist in root directory", + }; + case "android": + return { + info: "Whether android directory exists in the project", + error: "Android directory does not exist in root directory", + }; case "expo": return { info: "Whether supported version of Expo SDK is installed.", diff --git a/packages/vscode-extension/src/webview/views/DiagnosticView.tsx b/packages/vscode-extension/src/webview/views/DiagnosticView.tsx index a7fe162fc..8aad2c769 100644 --- a/packages/vscode-extension/src/webview/views/DiagnosticView.tsx +++ b/packages/vscode-extension/src/webview/views/DiagnosticView.tsx @@ -28,6 +28,7 @@ function DiagnosticView() { name="androidEmulator" info={dependencies.androidEmulator} /> +
{Platform.OS === "macos" && ( @@ -35,6 +36,7 @@ function DiagnosticView() { +
)}