Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move from activity bar to secondary bar hint #24

Merged
merged 7 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ The only thing you need to do is open your React Native of Expo project as works
Once you have it open, you can start the extension panel in one of a few ways:

1. When you open any file of your project to edit it, you can launch the extension from "Open IDE Panel" button in the editor toolbar:
<img width="800" alt="sztudio_editor_button" src="https://github.com/software-mansion-labs/react-native-ide/assets/726445/18983660-0a06-4b56-ba3f-2eda2bf50f12">
<img width="800" alt="sztudio_editor_button" src="https://github.com/software-mansion-labs/react-native-ide/assets/726445/18983660-0a06-4b56-ba3f-2eda2bf50f12">
2. You can use "React Native IDE: Open IDE Panel" available in vscode's command palette:
<img width="800" alt="sztudio_command_palette" src="https://github.com/software-mansion-labs/react-native-ide/assets/726445/ea7579b1-fc40-47c2-9d1c-50907ec9d665">
<img width="800" alt="sztudio_command_palette" src="https://github.com/software-mansion-labs/react-native-ide/assets/726445/ea7579b1-fc40-47c2-9d1c-50907ec9d665">
3. If you already had the panel open in this project before restarting the editor, it will automatically reopen in the same place.

## 2. Create simulator and emulator instances on the first run

When you open the IDE panel for the first time, it'll ask you to configure Android emulator of iOS simulator.
Depending on which platform you want to run your app on first, click one of the options available at the initial screen:

<img width="650" alt="sztudio-init-screen" src="https://github.com/software-mansion-labs/react-native-ide/assets/726445/d2c6a55a-2f22-46fe-917b-686766ad1f8e">

You will be able to add or remove simulators later using the device menu in the left bottom corner of the panel.
Expand All @@ -28,9 +29,13 @@ Please follow the [SIMULATORS](SIMULATORS.md) section to learn how to manage sys

## 3. Decide on the location of the IDE panel

The main extension window can be either presented as one of the editor tabs, which is the default behavior, or as a side panel.
To change between these two modes, open VSCode settings and search for "React Native IDE: Show Panel in Activity Bar" option.
Note that when the extension is used as side panel it can be dragged to the secondary side panel that's on the opposite side to where your file explorer is placed:
The main extension window can be either presented as one of the editor tabs, which is the default behavior, or as a side panel (in primary or secondary side panel location).
To change between these modes, you can either use React Native IDE section in the VSCode settings, or use the dropdown menu from the right top corner in the IDE panel:

<img width="450" alt="sztudio-change-position" src="https://github.com/software-mansion-labs/react-native-ide/assets/726445/5540bce1-855a-4e77-8c22-a5429b6d90d9">

Here is how the IDE would look like when place in the side panel:

<img width="800" alt="sztudio-side-panel" src="https://github.com/software-mansion-labs/react-native-ide/assets/726445/fdb01232-c735-40e1-bf75-a6cbdef5d9a6">

## 4. Wait for the project to build and run
Expand Down
17 changes: 11 additions & 6 deletions packages/vscode-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@
"default": null,
"description": "Location of the React Native application root folder relative to the workspace workspace. This is used for monorepo type setups when the workspace root is not the root of the React Native project. The IDE extension tries to locate the React Native application root automatically, but in case it failes to do so (i.e. there are multiple applications defined in the workspace), you can use this setting to override the location."
},
"ReactNativeIDE.showPanelInActivityBar":{
"type": "boolean",
"ReactNativeIDE.panelLocation": {
"type": "string",
"scope": "window",
"default": false,
"description": "This option alows you to move IDE Panel to Activity Bar. (warning: if you currently have it open it is going to be close after ajusting that setting.)"
"default": "tab",
"enum": [
"tab",
"side-panel",
"secondary-side-panel"
],
"description": "Controlls location of the IDE panel. Due to vscode API limitations, when secondary side panel is selected, you need to manually move the IDE panel to the secondary side panel. Changing this option closes and reopens the IDE."
}
}
},
Expand All @@ -75,7 +80,7 @@
"type": "webview",
"id": "ReactNativeIDE.view",
"name": "IDE Panel",
"when": "config.ReactNativeIDE.showPanelInActivityBar"
"when": "config.ReactNativeIDE.panelLocation != 'tab'"
}
]
},
Expand All @@ -84,7 +89,7 @@
{
"command": "RNIDE.openPanel",
"group": "navigation",
"when": "RNIDE.extensionIsActive && !RNIDE.panelIsOpen && !config.ReactNativeIDE.showPanelInActivityBar"
"when": "RNIDE.extensionIsActive && !RNIDE.panelIsOpen"
}
]
},
Expand Down
1 change: 0 additions & 1 deletion packages/vscode-extension/src/common/Project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

// important: order of values in this enum matters
export enum StartupMessage {
InitializingDevice = "Initializing device",

Check warning on line 27 in packages/vscode-extension/src/common/Project.ts

View workflow job for this annotation

GitHub Actions / check

Enum Member name `InitializingDevice` must match one of the following formats: camelCase
StartingPackager = "Starting packager",

Check warning on line 28 in packages/vscode-extension/src/common/Project.ts

View workflow job for this annotation

GitHub Actions / check

Enum Member name `StartingPackager` must match one of the following formats: camelCase
BootingDevice = "Booting device",
Building = "Building",
Installing = "Installing",
Expand Down Expand Up @@ -79,7 +79,6 @@
focusBuildOutput(): Promise<void>;
focusExtensionLogsOutput(): Promise<void>;
focusDebugConsole(): Promise<void>;

openNavigation(navigationItemID: string): Promise<void>;

dispatchTouch(xRatio: number, yRatio: number, type: "Up" | "Move" | "Down"): Promise<void>;
Expand Down
31 changes: 31 additions & 0 deletions packages/vscode-extension/src/common/WorkspaceConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export type PanelLocation = "tab" | "side-panel" | "secondary-side-panel";

export type WorkspaceConfigProps = {
panelLocation: PanelLocation;
relativeAppLocation: string;
};

export interface WorkspaceConfigEventMap {
configChange: WorkspaceConfigProps;
}

export interface WorkspaceConfigEventListener<T> {
(event: T): void;
}

export interface WorkspaceConfig {
getConfig(): Promise<WorkspaceConfigProps>;
// update method can take any of the keys from WorkspaceConfigProps and appropriate value:
update<K extends keyof WorkspaceConfigProps>(
key: K,
value: WorkspaceConfigProps[K]
): Promise<void>;
addListener<K extends keyof WorkspaceConfigEventMap>(
eventType: K,
listener: WorkspaceConfigEventListener<WorkspaceConfigEventMap[K]>
): Promise<void>;
removeListener<K extends keyof WorkspaceConfigEventMap>(
eventType: K,
listener: WorkspaceConfigEventListener<WorkspaceConfigEventMap[K]>
): Promise<void>;
}
62 changes: 27 additions & 35 deletions packages/vscode-extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import {
Uri,
ExtensionContext,
ExtensionMode,
DebugConfigurationProviderTriggerKind,
ConfigurationChangeEvent,
DebugConfigurationProviderTriggerKind,
} from "vscode";
import { Tabpanel } from "./panels/Tabpanel";
import { TabPanel } from "./panels/Tabpanel";
import { PreviewCodeLensProvider } from "./providers/PreviewCodeLensProvider";
import { DebugConfigProvider } from "./providers/DebugConfigProvider";
import { DebugAdapterDescriptorFactory } from "./debugging/DebugAdapterDescriptorFactory";
Expand All @@ -24,7 +24,8 @@ import { command } from "./utilities/subprocess";
import path from "path";
import os from "os";
import fs from "fs";
import { SidepanelViewProvider } from "./panels/SidepanelViewProvider";
import { SidePanelViewProvider } from "./panels/SidepanelViewProvider";
import { PanelLocation } from "./common/WorkspaceConfig";

const BIN_MODIFICATION_DATE_KEY = "bin_modification_date";
const OPEN_PANEL_ON_ACTIVATION = "open_panel_on_activation";
Expand Down Expand Up @@ -54,38 +55,32 @@ export function deactivate(context: ExtensionContext): undefined {

export async function activate(context: ExtensionContext) {
handleUncaughtErrors();
IDEPanelLocationListener();

setExtensionContext(context);
if (context.extensionMode === ExtensionMode.Development) {
enableDevModeLogging();
}

await fixBinaries(context);

function showIDEPanel(fileName?: string, lineNumber?: number) {
if (
workspace.getConfiguration("ReactNativeIDE").get<PanelLocation>("panelLocation") !== "tab"
) {
SidePanelViewProvider.showView(context, fileName, lineNumber);
} else {
TabPanel.render(context, fileName, lineNumber);
}
}

context.subscriptions.push(
window.registerWebviewViewProvider(
SidepanelViewProvider.viewType,
new SidepanelViewProvider(context)
SidePanelViewProvider.viewType,
new SidePanelViewProvider(context)
)
);
context.subscriptions.push(
commands.registerCommand("RNIDE.openPanel", (fileName?: string, lineNumber?: number) => {
if (workspace.getConfiguration("ReactNativeIDE").get<boolean>("showPanelInActivityBar")) {
SidepanelViewProvider.showView(context, fileName, lineNumber);
} else {
Tabpanel.render(context, fileName, lineNumber);
}
})
);
context.subscriptions.push(
commands.registerCommand("RNIDE.showPanel", (fileName?: string, lineNumber?: number) => {
if (workspace.getConfiguration("ReactNativeIDE").get<boolean>("showPanelInActivityBar")) {
SidepanelViewProvider.showView(context, fileName, lineNumber);
} else {
Tabpanel.render(context, fileName, lineNumber);
}
})
);
context.subscriptions.push(commands.registerCommand("RNIDE.openPanel", showIDEPanel));
context.subscriptions.push(commands.registerCommand("RNIDE.showPanel", showIDEPanel));
context.subscriptions.push(
commands.registerCommand("RNIDE.diagnose", diagnoseWorkspaceStructure)
);
Expand Down Expand Up @@ -115,18 +110,15 @@ export async function activate(context: ExtensionContext) {
)
);

await configureAppRootFolder();
}
context.subscriptions.push(
workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
if (event.affectsConfiguration("ReactNativeIDE.panelLocation")) {
showIDEPanel();
}
})
);

function IDEPanelLocationListener() {
workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
if (!event.affectsConfiguration("ReactNativeIDE")) {
return;
}
if (workspace.getConfiguration("ReactNativeIDE").get("showPanelInActivityBar")) {
Tabpanel.currentPanel?.dispose();
}
});
await configureAppRootFolder();
}

async function findSingleFileInWorkspace(fileGlobPattern: string, excludePattern: string | null) {
Expand Down
28 changes: 20 additions & 8 deletions packages/vscode-extension/src/panels/SidepanelViewProvider.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { ExtensionContext, Uri, WebviewView, WebviewViewProvider, commands } from "vscode";
import {
ExtensionContext,
Uri,
WebviewView,
WebviewViewProvider,
commands,
workspace,
} from "vscode";
import { generateWebviewContent } from "./webviewContentGenerator";
import { extensionContext } from "../utilities/extensionContext";

import { WebviewController } from "./WebviewController";
import { Logger } from "../Logger";

export class SidepanelViewProvider implements WebviewViewProvider {
export class SidePanelViewProvider implements WebviewViewProvider {
public static readonly viewType = "ReactNativeIDE.view";
public static currentProvider: SidepanelViewProvider | undefined;
public static currentProvider: SidePanelViewProvider | undefined;
private _view: any = null;
private webviewController: any = null;

constructor(private readonly context: ExtensionContext) {
SidepanelViewProvider.currentProvider = this;
SidePanelViewProvider.currentProvider = this;
}

refresh(): void {
Expand All @@ -23,15 +30,20 @@ export class SidepanelViewProvider implements WebviewViewProvider {
}

public static showView(context: ExtensionContext, fileName?: string, lineNumber?: number) {
if (SidepanelViewProvider.currentProvider) {
commands.executeCommand(`${SidepanelViewProvider.viewType}.focus`);
if (SidePanelViewProvider.currentProvider) {
commands.executeCommand(`${SidePanelViewProvider.viewType}.focus`);
if (
workspace.getConfiguration("ReactNativeIDE").get("panelLocation") === "secondary-side-panel"
) {
commands.executeCommand("workbench.action.focusAuxiliaryBar");
}
} else {
Logger.error("SidepanelViewProvider does not exist.");
return;
}

if (fileName !== undefined && lineNumber !== undefined) {
SidepanelViewProvider.currentProvider.webviewController.project.startPreview(
SidePanelViewProvider.currentProvider.webviewController.project.startPreview(
`preview:/${fileName}:${lineNumber}`
);
}
Expand Down
35 changes: 26 additions & 9 deletions packages/vscode-extension/src/panels/Tabpanel.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { WebviewPanel, window, Uri, ViewColumn, ExtensionContext, commands } from "vscode";
import {
WebviewPanel,
window,
Uri,
ViewColumn,
ExtensionContext,
commands,
workspace,
ConfigurationChangeEvent,
} from "vscode";

import { extensionContext } from "../utilities/extensionContext";
import { generateWebviewContent } from "./webviewContentGenerator";
import { WebviewController } from "./WebviewController";

const OPEN_PANEL_ON_ACTIVATION = "open_panel_on_activation";

export class Tabpanel {
public static currentPanel: Tabpanel | undefined;
export class TabPanel {
public static currentPanel: TabPanel | undefined;
private readonly _panel: WebviewPanel;
private webviewController: WebviewController;

Expand All @@ -26,12 +35,21 @@ export class Tabpanel {
);

this.webviewController = new WebviewController(this._panel.webview);

workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
if (!event.affectsConfiguration("ReactNativeIDE")) {
return;
}
if (workspace.getConfiguration("ReactNativeIDE").get("panelLocation") !== "tab") {
this.dispose();
}
});
}

public static render(context: ExtensionContext, fileName?: string, lineNumber?: number) {
if (Tabpanel.currentPanel) {
if (TabPanel.currentPanel) {
// If the webview panel already exists reveal it
Tabpanel.currentPanel._panel.reveal(ViewColumn.Beside);
TabPanel.currentPanel._panel.reveal(ViewColumn.Beside);
} else {
// If a webview panel does not already exist create and show a new one

Expand All @@ -51,15 +69,14 @@ export class Tabpanel {
retainContextWhenHidden: true,
}
);
Tabpanel.currentPanel = new Tabpanel(panel);
TabPanel.currentPanel = new TabPanel(panel);
context.workspaceState.update(OPEN_PANEL_ON_ACTIVATION, true);

commands.executeCommand("workbench.action.lockEditorGroup");
commands.executeCommand("setContext", "RNIDE.panelIsOpen", true);
}

if (fileName !== undefined && lineNumber !== undefined) {
Tabpanel.currentPanel.webviewController.project.startPreview(
TabPanel.currentPanel.webviewController.project.startPreview(
`preview:/${fileName}:${lineNumber}`
);
}
Expand All @@ -71,7 +88,7 @@ export class Tabpanel {
// key in this case to prevent extension from automatically opening the panel next time they open the editor
extensionContext.workspaceState.update(OPEN_PANEL_ON_ACTIVATION, undefined);

Tabpanel.currentPanel = undefined;
TabPanel.currentPanel = undefined;

// Dispose of the current webview panel
this._panel.dispose();
Expand Down
Loading
Loading