diff --git a/src/io/flutter/sdk/FlutterSdk.java b/src/io/flutter/sdk/FlutterSdk.java index a671f1265..5f85e68f6 100644 --- a/src/io/flutter/sdk/FlutterSdk.java +++ b/src/io/flutter/sdk/FlutterSdk.java @@ -416,7 +416,7 @@ public FlutterCommand flutterTest(@NotNull PubRoot root, @NotNull VirtualFile fi } @NotNull - public FlutterCommand widgetPreview(@NotNull PubRoot root, boolean isVerboseMode) { + public FlutterCommand widgetPreview(@NotNull PubRoot root, boolean isVerboseMode, @Nullable String dtdUri, @Nullable String devToolsUri) { final List args = new ArrayList<>(); args.add("start"); args.add("--web-server"); @@ -424,6 +424,12 @@ public FlutterCommand widgetPreview(@NotNull PubRoot root, boolean isVerboseMode if (isVerboseMode) { args.add("--verbose"); } + if (dtdUri != null) { + args.add("--dtd-url=" + dtdUri); + } + if (devToolsUri != null) { + args.add("--devtools-server-address=" + devToolsUri); + } return new FlutterCommand(this, root.getRoot(), FlutterCommand.Type.WIDGET_PREVIEW, args.toArray(new String[]{})); } diff --git a/src/io/flutter/widgetpreview/WidgetPreviewPanel.java b/src/io/flutter/widgetpreview/WidgetPreviewPanel.java index 89052b87f..ba8cc14ca 100644 --- a/src/io/flutter/widgetpreview/WidgetPreviewPanel.java +++ b/src/io/flutter/widgetpreview/WidgetPreviewPanel.java @@ -7,18 +7,22 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.EditorColorsListener; import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindow; import com.intellij.util.messages.MessageBusConnection; +import com.jetbrains.lang.dart.ide.toolingDaemon.DartToolingDaemonService; import icons.FlutterIcons; import io.flutter.FlutterBundle; import io.flutter.FlutterUtils; +import io.flutter.dart.DtdUtils; +import io.flutter.devtools.DevToolsUrl; import io.flutter.devtools.DevToolsUtils; import io.flutter.logging.PluginLogger; import io.flutter.pub.PubRoot; +import io.flutter.run.daemon.DevToolsInstance; +import io.flutter.run.daemon.DevToolsService; import io.flutter.sdk.FlutterCommand; import io.flutter.sdk.FlutterSdk; import io.flutter.sdk.FlutterSdkVersion; @@ -27,8 +31,8 @@ import io.flutter.utils.OpenApiUtils; import io.flutter.view.BrowserUrlProvider; import io.flutter.view.EmbeddedTab; -import io.flutter.view.WidgetPreviewUrlProvider; import io.flutter.view.ViewUtils; +import io.flutter.view.WidgetPreviewUrlProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +41,8 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -67,7 +73,7 @@ public WidgetPreviewPanel(@NotNull Project project, @NotNull ToolWindow toolWind } private void startWidgetPreview() { - ApplicationManager.getApplication().executeOnPooledThread(() -> { + OpenApiUtils.safeExecuteOnPooledThread(() -> { try { // Check versioning of Flutter SDK. FlutterSdk sdk = FlutterSdk.getFlutterSdk(project); @@ -102,7 +108,9 @@ private void startWidgetPreview() { } boolean isVerboseMode = FlutterSettings.getInstance().isVerboseLogging(); - final FlutterCommand command = sdk.widgetPreview(root, isVerboseMode); + final String dtdUri = getDtdUri(); + final String devToolsUri = getDevToolsUri(); + final FlutterCommand command = sdk.widgetPreview(root, isVerboseMode, dtdUri, devToolsUri); LOG.info(command.getDisplayCommand()); final ProcessHandler handler = new MostlySilentColoredProcessHandler(command.createGeneralCommandLine(project)); @@ -120,6 +128,43 @@ private void startWidgetPreview() { }); } + private @Nullable String getDevToolsUri() { + try { + final CompletableFuture devToolsFuture = DevToolsService.getInstance(project).getDevToolsInstance(); + if (devToolsFuture == null) { + LOG.error("DevTools future is null."); + return null; + } + + final DevToolsInstance instance = devToolsFuture.get(30, TimeUnit.SECONDS); + if (instance == null) { + LOG.error("DevTools instance is null."); + return null; + } + return new DevToolsUrl.Builder().setDevToolsHost(instance.host()).setDevToolsPort(instance.port()).build().getUrlString(); + } + catch (InterruptedException | java.util.concurrent.ExecutionException | TimeoutException e) { + LOG.error("DevTools service failed: ", e); + } + return null; + } + + private @Nullable String getDtdUri() { + try { + final DartToolingDaemonService dtd = new DtdUtils().readyDtdService(project).get(30, TimeUnit.SECONDS); + if (dtd == null) { + LOG.error("DTD service is null."); + return null; + } + + return dtd.getUri(); + } + catch (TimeoutException | java.util.concurrent.ExecutionException | InterruptedException e) { + LOG.error("DTD service is not available after 30 seconds.", e); + } + return null; + } + // This is intended for the first time we load the panel - save the URL and listen for changes. private void setUrlAndLoad(@NotNull String url) { this.urlProvider = new WidgetPreviewUrlProvider(url, new DevToolsUtils().getIsBackgroundBright()); @@ -142,19 +187,18 @@ private void loadUrl(@NotNull BrowserUrlProvider urlProvider) { }); } + // TODO(https://github.com/flutter/flutter/issues/177945): Ideally widget preview would change colors based on theme changes events, + // which we already send for the DevTools panels. If this is implemented then we can remove this listening code. private void listenForReload() { MessageBusConnection connection = project.getMessageBus().connect(); - connection.subscribe(EditorColorsManager.TOPIC, new EditorColorsListener() { - @Override - public void globalSchemeChange(@Nullable EditorColorsScheme scheme) { - if (urlProvider == null) { - return; - } + connection.subscribe(EditorColorsManager.TOPIC, (EditorColorsListener)scheme -> { + if (urlProvider == null) { + return; + } - final boolean changed = urlProvider.maybeUpdateColor(); - if (changed) { - loadUrl(urlProvider); - } + final boolean changed = urlProvider.maybeUpdateColor(); + if (changed) { + loadUrl(urlProvider); } }); Disposer.register(toolWindow.getDisposable(), connection);