Skip to content

Commit

Permalink
Add embedded view for other DevTools tabs (#7496)
Browse files Browse the repository at this point in the history
No app running:
<img width="498" alt="Screenshot 2024-06-07 at 2 22 32 PM"
src="https://github.com/flutter/flutter-intellij/assets/6379305/240f0fab-76b9-4c1f-a955-fa47c8fdf960">

App running:
<img width="522" alt="Screenshot 2024-06-07 at 2 23 24 PM"
src="https://github.com/flutter/flutter-intellij/assets/6379305/55c8663e-92c3-471c-9c9b-638ee3faf022">

Review after #7417 is
merged

Partially addresses
#7195
  • Loading branch information
helin24 committed Jun 21, 2024
1 parent 38cdeff commit a2227bf
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 11 deletions.
2 changes: 2 additions & 0 deletions flutter-idea/src/io/flutter/FlutterInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import io.flutter.analytics.UnifiedAnalytics;
import io.flutter.android.IntelliJAndroidSdk;
import io.flutter.bazel.WorkspaceCache;
import io.flutter.devtools.RemainingDevToolsViewFactory;
import io.flutter.editor.FlutterSaveActionsManager;
import io.flutter.logging.FlutterConsoleLogManager;
import io.flutter.module.FlutterModuleBuilder;
Expand Down Expand Up @@ -261,6 +262,7 @@ private void initializeToolWindows(@NotNull Project project) {
FlutterViewFactory.init(project);
FlutterPerformanceViewFactory.init(project);
PreviewViewFactory.init(project);
RemainingDevToolsViewFactory.init(project);
toolWindowsInitialized = true;
}

Expand Down
23 changes: 21 additions & 2 deletions flutter-idea/src/io/flutter/devtools/DevToolsUrl.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@
public class DevToolsUrl {
private String devToolsHost;
private int devToolsPort;
private String vmServiceUri;
public String vmServiceUri;
private String page;
private boolean embed;
public String colorHexCode;
public Boolean isBright;
public String widgetId;
public Float fontSize;
public String hide;
private final FlutterSdkVersion flutterSdkVersion;
private final FlutterSdkUtil sdkUtil;

Expand All @@ -44,6 +45,7 @@ public static class Builder {
private Boolean embed;
private String widgetId;
private Float fontSize;
private String hide;

private FlutterSdkVersion flutterSdkVersion;
private WorkspaceCache workspaceCache;
Expand Down Expand Up @@ -90,6 +92,11 @@ public Builder setFontSize(Float fontSize) {
return this;
}

public Builder setHide(String hide) {
this.hide = hide;
return this;
}

public Builder setDevToolsUtils(DevToolsUtils devToolsUtils) {
this.devToolsUtils = devToolsUtils;
return this;
Expand Down Expand Up @@ -141,6 +148,7 @@ private DevToolsUrl(Builder builder) {
this.isBright = builder.devToolsUtils.getIsBackgroundBright();
this.fontSize = builder.devToolsUtils.getFontSize();
}
this.hide = builder.hide;
this.widgetId = builder.widgetId;
this.flutterSdkVersion = builder.flutterSdkVersion;
this.ideFeature = builder.ideFeature;
Expand Down Expand Up @@ -174,7 +182,18 @@ public String getUrlString() {
params.add("theme=" + (isBright ? "light" : "dark"));
}
if (embed) {
params.add(this.canUseMultiEmbed ? "embedMode=one" : "embed=true");
if (!this.canUseMultiEmbed) {
// This is for older versions of DevTools that do not support embed= one vs. many.
params.add("embed=true");
} else {
if (hide != null) {
// If we are using the hide param, we can assume that we are trying to embed multiple tabs.
params.add("embedMode=many");
params.add("hide=" + hide);
} else {
params.add("embedMode=one");
}
}
}
if (fontSize != null) {
params.add("fontSize=" + fontSize);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2024 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
package io.flutter.devtools;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.ui.content.ContentManager;
import io.flutter.FlutterUtils;
import io.flutter.bazel.WorkspaceCache;
import io.flutter.run.daemon.DevToolsService;
import io.flutter.sdk.FlutterSdk;
import io.flutter.sdk.FlutterSdkVersion;
import io.flutter.utils.AsyncUtils;
import io.flutter.view.FlutterViewMessages;
import kotlin.coroutines.Continuation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;

public class RemainingDevToolsViewFactory implements ToolWindowFactory {
public static void init(Project project) {
project.getMessageBus().connect().subscribe(
FlutterViewMessages.FLUTTER_DEBUG_TOPIC, (FlutterViewMessages.FlutterDebugNotifier)event -> initView(project, event)
);
}

private static void initView(Project project, FlutterViewMessages.FlutterDebugEvent event) {
RemainingDevToolsViewService service = project.getService(RemainingDevToolsViewService.class);
String vmServiceUri = event.app.getConnector().getBrowserUrl();
if (vmServiceUri == null) return;
service.updateVmServiceUri(vmServiceUri);
}


@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow window) {
final ContentManager contentManager = window.getContentManager();
FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
FlutterSdkVersion sdkVersion = sdk == null ? null : sdk.getVersion();
RemainingDevToolsViewService service = project.getService(RemainingDevToolsViewService.class);

AsyncUtils.whenCompleteUiThread(
DevToolsService.getInstance(project).getDevToolsInstance(),
(instance, error) -> {
// Skip displaying if the project has been closed.
if (!project.isOpen()) {
return;
}

if (error != null) {
return;
}

if (instance == null) {
return;
}

final DevToolsUrl devToolsUrl = new DevToolsUrl.Builder()
.setDevToolsHost(instance.host)
.setDevToolsPort(instance.port)
.setHide("home,inspector,deep-links,extensions")
.setEmbed(true).setFlutterSdkVersion(sdkVersion)
.setWorkspaceCache(WorkspaceCache.getInstance(project))
.setIdeFeature(DevToolsIdeFeature.TOOL_WINDOW)
.build();

ApplicationManager.getApplication().invokeLater(() -> {
Optional.ofNullable(
FlutterUtils.embeddedBrowser(project))
.ifPresent(embeddedBrowser -> {
service.setEmbeddedBrowser(embeddedBrowser);
embeddedBrowser.openPanel(window, "Flutter DevTools", devToolsUrl, (String err) -> {
System.out.println(err);
});
});
});
}
);
}

@Nullable
@Override
public Object isApplicableAsync(@NotNull Project project, @NotNull Continuation<? super Boolean> $completion) {
FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
FlutterSdkVersion sdkVersion = sdk == null ? null : sdk.getVersion();
return sdkVersion != null && sdkVersion.canUseDevToolsMultiEmbed();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2024 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
package io.flutter.devtools;

import com.intellij.openapi.components.Service;
import com.intellij.openapi.project.Project;
import io.flutter.view.EmbeddedBrowser;
import org.jetbrains.annotations.NotNull;

@Service(Service.Level.PROJECT)
public final class RemainingDevToolsViewService {
private final Project myProject;
private EmbeddedBrowser embeddedBrowser;

RemainingDevToolsViewService(Project project) {
this.myProject = project;
}

public void setEmbeddedBrowser(EmbeddedBrowser embeddedBrowser) {
this.embeddedBrowser = embeddedBrowser;
}

public void updateVmServiceUri(@NotNull String vmServiceUri) {
if (this.embeddedBrowser == null) return;
this.embeddedBrowser.updateVmServiceUri(vmServiceUri);
}
}
34 changes: 25 additions & 9 deletions flutter-idea/src/io/flutter/view/EmbeddedBrowser.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public abstract class EmbeddedBrowser {
protected final Map<@NotNull String, Map<@NotNull String, @NotNull BrowserTab>> windows = new HashMap<>();

public abstract Logger logger();

private final Analytics analytics;

private DevToolsUrl url;
Expand All @@ -62,14 +63,15 @@ public EmbeddedBrowser(Project project) {
ProjectManager.getInstance().addProjectManagerListener(project, new ProjectManagerListener() {
@Override
public void projectClosing(@NotNull Project project) {
for (final String window: windows.keySet()) {
for (final String window : windows.keySet()) {
final Map<String, BrowserTab> tabs = windows.get(window);
for (final String tabName: tabs.keySet()) {
for (final String tabName : tabs.keySet()) {
final BrowserTab tab = tabs.get(tabName);
if (tab.embeddedTab != null) {
try {
tab.embeddedTab.close();
} catch (Exception ex) {
}
catch (Exception ex) {
logger().info(ex);
}
}
Expand All @@ -89,7 +91,8 @@ public void openPanel(ToolWindow toolWindow, String tabName, DevToolsUrl devTool
if (firstTab == null) {
try {
tabs.put(tabName, openBrowserTabFor(tabName, toolWindow));
} catch (Exception ex) {
}
catch (Exception ex) {
analytics.sendEvent(ANALYTICS_CATEGORY, "openBrowserTabFailed-" + this.getClass());
onBrowserUnavailable.accept(ex.getMessage());
return;
Expand All @@ -109,7 +112,8 @@ public void openPanel(ToolWindow toolWindow, String tabName, DevToolsUrl devTool
try {
final String url = devToolsUrl.getUrlString();
tab.embeddedTab.loadUrl(url);
} catch (Exception ex) {
}
catch (Exception ex) {
tab.devToolsUrlFuture.completeExceptionally(ex);
onBrowserUnavailable.accept(ex.getMessage());
logger().info(ex);
Expand All @@ -127,7 +131,7 @@ public void openPanel(ToolWindow toolWindow, String tabName, DevToolsUrl devTool

tab.contentManager.removeAllContents(false);

for (final String otherTabName: tabs.keySet()) {
for (final String otherTabName : tabs.keySet()) {
if (otherTabName.equals(tabName)) {
continue;
}
Expand All @@ -149,7 +153,8 @@ private void openLinkInStandardBrowser(ContentManager contentManager) {
verifyEventDispatchThread();
if (url == null) {
showMessage("The URL is invalid.", contentManager);
} else {
}
else {
BrowserLauncher.getInstance().browse(
url.getUrlString(),
null
Expand All @@ -160,7 +165,7 @@ private void openLinkInStandardBrowser(ContentManager contentManager) {
}

protected void verifyEventDispatchThread() {
assert(SwingUtilities.isEventDispatchThread());
assert (SwingUtilities.isEventDispatchThread());
}

protected void showMessageWithUrlLink(@NotNull String message, ContentManager contentManager) {
Expand Down Expand Up @@ -192,7 +197,8 @@ protected void showLabels(List<LabelInput> labels, ContentManager contentManager
descriptionLabel.setBorder(JBUI.Borders.empty(5));
descriptionLabel.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(descriptionLabel, BorderLayout.NORTH);
} else {
}
else {
final LinkLabel<String> linkLabel = new LinkLabel<>("<html>" + input.text + "</html>", null);
linkLabel.setBorder(JBUI.Borders.empty(5));
linkLabel.setListener(input.listener, null);
Expand Down Expand Up @@ -254,6 +260,16 @@ public void updateFontSize(float newFontSize) {
});
}

public void updateVmServiceUri(@NotNull String newVmServiceUri) {
updateUrlAndReload(devToolsUrl -> {
if (newVmServiceUri.equals(devToolsUrl.vmServiceUri)) {
return null;
}
devToolsUrl.vmServiceUri = newVmServiceUri;
return devToolsUrl;
});
}

private void updateUrlAndReload(Function<DevToolsUrl, DevToolsUrl> newDevToolsUrlFn) {
this.windows.forEach((window, tabs) -> {
tabs.forEach((tabName, tab) -> {
Expand Down
1 change: 1 addition & 0 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@
<projectService serviceImplementation="io.flutter.performance.FlutterPerformanceView" overrides="false"/>

<toolWindow id="Flutter Deep Links" anchor="right" icon="FlutterIcons.Flutter_13" factoryClass="io.flutter.deeplinks.DeepLinksViewFactory" />
<toolWindow id="Flutter DevTools" anchor="right" icon="FlutterIcons.Flutter_13" factoryClass="io.flutter.devtools.RemainingDevToolsViewFactory" />

<projectOpenProcessor id="flutter" implementation="io.flutter.project.FlutterProjectOpenProcessor" order="first"/>

Expand Down
1 change: 1 addition & 0 deletions resources/META-INF/plugin_template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@
<projectService serviceImplementation="io.flutter.performance.FlutterPerformanceView" overrides="false"/>

<toolWindow id="Flutter Deep Links" anchor="right" icon="FlutterIcons.Flutter_13" factoryClass="io.flutter.deeplinks.DeepLinksViewFactory" />
<toolWindow id="Flutter DevTools" anchor="right" icon="FlutterIcons.Flutter_13" factoryClass="io.flutter.devtools.RemainingDevToolsViewFactory" />

<projectOpenProcessor id="flutter" implementation="io.flutter.project.FlutterProjectOpenProcessor" order="first"/>

Expand Down

0 comments on commit a2227bf

Please sign in to comment.