Skip to content

Remove dependencies on built-in Flutter icons #5824

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

Merged
merged 2 commits into from
Oct 15, 2021
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
1 change: 1 addition & 0 deletions gen/icons/FlutterIcons.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ private static Icon load(String path) {

public static final Icon Phone = load("/icons/phone.png");
public static final Icon Feedback = load("/icons/feedback.png");
public static final Icon RefreshItems = load("/icons/frefresh_items.png");

public static final Icon Dart_16 = load("/icons/dart_16.svg");

Expand Down
Binary file added resources/icons/refresh_items.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/io/flutter/actions/DeviceSelectorRefresherAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import io.flutter.editor.FlutterMaterialIcons;
import icons.FlutterIcons;
import io.flutter.run.daemon.DeviceService;
import io.flutter.utils.FlutterModuleUtils;
import org.jetbrains.annotations.NotNull;

public class DeviceSelectorRefresherAction extends AnAction {
public DeviceSelectorRefresherAction() {
super(FlutterMaterialIcons.getIconForName("refresh"));
super(FlutterIcons.RefreshItems);
}

@Override
Expand Down
9 changes: 5 additions & 4 deletions src/io/flutter/editor/FlutterCompletionContributor.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class FlutterCompletionContributor extends DartCompletionExtension {
@Override
@Nullable
public LookupElementBuilder createLookupElement(@NotNull final Project project, @NotNull final CompletionSuggestion suggestion) {
final Icon icon = findIcon(suggestion);
final Icon icon = findIcon(suggestion, project);
if (icon != null) {
final LookupElementBuilder lookup =
DartServerCompletionContributor.createLookupElement(project, suggestion).withTypeText("", icon, false);
Expand All @@ -38,7 +38,8 @@ public LookupElementBuilder createLookupElement(@NotNull final Project project,
return null;
}

private static Icon findIcon(@NotNull final CompletionSuggestion suggestion) {
@Nullable
private static Icon findIcon(@NotNull final CompletionSuggestion suggestion, @NotNull Project project) {
final Element element = suggestion.getElement();
if (element != null) {
final String returnType = element.getReturnType();
Expand All @@ -59,12 +60,12 @@ else if (Objects.equals(declaringType, "CupertinoColors")) {
}
}
else if (Objects.equals(declaringType, "Icons")) {
final Icon icon = FlutterMaterialIcons.getIconForName(name);
final Icon icon = FlutterIconLineMarkerProvider.getMaterialIconByName(project, name);
// If we have no icon, show an empty node (which is preferable to the default "IconData" text).
return icon != null ? icon : EMPTY_ICON;
}
else if (Objects.equals(declaringType, "CupertinoIcons")) {
final Icon icon = FlutterCupertinoIcons.getIconForName(name);
final Icon icon = FlutterIconLineMarkerProvider.getCupertinoIconByName(project, name);
// If we have no icon, show an empty node (which is preferable to the default "IconData" text).
return icon != null ? icon : EMPTY_ICON;
}
Expand Down
115 changes: 75 additions & 40 deletions src/io/flutter/editor/FlutterIconLineMarkerProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,40 @@ public static void initialize() {
BuiltInPaths.put("CupertinoIcons", CupertinoRelativeIconsPath);
}

@Nullable
public static Icon getCupertinoIconByName(@Nullable Project project, @NotNull String iconName) {
if (project == null) return null;
final FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
if (sdk == null) return null;
final IconInfo iconDef =
findStandardDefinition("CupertinoIcons", iconName, project, sdk.getHomePath() + BuiltInPaths.get("CupertinoIcons"), sdk);
if (iconDef == null) return null;
final String path = FlutterSdkUtil.getPathToCupertinoIconsPackage(project);
// <pub_cache>/hosted/pub.dartlang.org/cupertino_icons-v.m.n/assets/CupertinoIcons.ttf
return findStandardIconFromDef(iconName, iconDef, path + CupertinoRelativeAssetPath);
}

@Nullable
public static Icon getMaterialIconByName(@Nullable Project project, @NotNull String iconName) {
if (project == null) return null;
final FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
if (sdk == null) return null;
final IconInfo iconDef =
findStandardDefinition("Icons", iconName, project, sdk.getHomePath() + BuiltInPaths.get("Icons"), sdk);
if (iconDef == null) return null;
// <flutter-sdk>/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf
return findStandardIconFromDef(iconName, iconDef, sdk.getHomePath() + MaterialRelativeAssetPath);
}

@Nullable
public static Icon getMaterialIconFromCodepoint(@Nullable Project project, int codepoint) {
if (project == null) return null;
final FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
if (sdk == null) return null;
final IconPreviewGenerator generator = new IconPreviewGenerator(sdk.getHomePath() + MaterialRelativeAssetPath);
return generator.convert(codepoint);
}

@Nullable("null means disabled")
@Override
public @GutterName String getName() {
Expand All @@ -87,9 +121,10 @@ public LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element) {
return sdk == null ? null : getLineMarkerInfo(element, sdk);
}

@SuppressWarnings("MissingRecentApi")
@VisibleForTesting
@Nullable
LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element, @NotNull FlutterSdk sdk) {
static LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element, @NotNull FlutterSdk sdk) {
if ((element.getNode() != null ? element.getNode().getElementType() : null) != DartTokenTypes.IDENTIFIER) return null;

final String name = element.getText();
Expand Down Expand Up @@ -146,30 +181,12 @@ LineMarkerInfo<?> getLineMarkerInfo(@NotNull PsiElement element, @NotNull Flutte
assert parentNode != null;
if (parentNode.getElementType() == DartTokenTypes.CALL_EXPRESSION) {
// Check font family and package
final DartArguments arguments = DartPsiImplUtil.getArguments((DartCallExpression)parent);
if (arguments == null) return null;
final String family = getValueOfNamedArgument(arguments, "fontFamily");
final PsiElement fontPackage = getNamedArgumentExpression(arguments, "fontPackage");
final String argument = getValueOfPositionalArgument(arguments, 0);
if (argument == null) return null;
final Icon icon = getIconFromPackage(fontPackage, family, argument, element.getProject(), sdk);
if (icon != null) {
return createLineMarker(element, icon);
}
return getIconFromArguments(DartPsiImplUtil.getArguments((DartCallExpression)parent), element, sdk);
}
else if (parentNode.getElementType() == DartTokenTypes.SIMPLE_TYPE) {
parent = getNewExprFromType(parent);
if (parent == null) return null;
final DartArguments arguments = DartPsiImplUtil.getArguments((DartNewExpression)parent);
if (arguments == null) return null;
final String family = getValueOfNamedArgument(arguments, "fontFamily");
final PsiElement fontPackage = getNamedArgumentExpression(arguments, "fontPackage");
final String argument = getValueOfPositionalArgument(arguments, 0);
if (argument == null) return null;
final Icon icon = getIconFromPackage(fontPackage, family, argument, element.getProject(), sdk);
if (icon != null) {
return createLineMarker(element, icon);
}
return getIconFromArguments(DartPsiImplUtil.getArguments((DartNewExpression)parent), element, sdk);
}
else {
final PsiElement idNode = refExpr.getFirstChild();
Expand All @@ -181,17 +198,10 @@ else if (parentNode.getElementType() == DartTokenTypes.SIMPLE_TYPE) {
final String selector = AstBufferUtil.getTextSkippingWhitespaceComments(selectorNode.getNode());
final Icon icon;
if (name.equals("Icons")) {
final IconInfo iconDef = findStandardDefinition(name, selector, element.getProject(), knownPath, sdk);
if (iconDef == null) return null;
// <flutter-sdk>/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf
icon = findStandardIconFromDef(name, iconDef, sdk.getHomePath() + MaterialRelativeAssetPath);
icon = getMaterialIconByName(element.getProject(), selector);
}
else if (name.equals("CupertinoIcons")) {
final IconInfo iconDef = findStandardDefinition(name, selector, element.getProject(), knownPath, sdk);
if (iconDef == null) return null;
final String path = FlutterSdkUtil.getPathToCupertinoIconsPackage(element.getProject());
// <pub_cache>/hosted/pub.dartlang.org/cupertino_icons-v.m.n/assets/CupertinoIcons.ttf
icon = findStandardIconFromDef(name, iconDef, path + CupertinoRelativeAssetPath);
icon = getCupertinoIconByName(element.getProject(), selector);
}
else {
// Note: I want to keep this code until I'm sure we won't use pubspec.yaml.
Expand Down Expand Up @@ -227,7 +237,24 @@ else if (name.equals("CupertinoIcons")) {
}

@Nullable
private IconInfo findStandardDefinition(@NotNull String className, @NotNull String iconName, @NotNull Project project, @Nullable String path, @NotNull FlutterSdk sdk) {
private static LineMarkerInfo<PsiElement> getIconFromArguments(@Nullable DartArguments arguments,
@NotNull PsiElement element,
@NotNull FlutterSdk sdk) {
if (arguments == null) return null;
final String family = getValueOfNamedArgument(arguments, "fontFamily");
final PsiElement fontPackage = getNamedArgumentExpression(arguments, "fontPackage");
final String argument = getValueOfPositionalArgument(arguments, 0);
if (argument == null) return null;
final Icon icon = getIconFromPackage(fontPackage, family, argument, element.getProject(), sdk);
return icon == null ? null : createLineMarker(element, icon);
}

@Nullable
private static IconInfo findStandardDefinition(@NotNull String className,
@NotNull String iconName,
@NotNull Project project,
@Nullable String path,
@NotNull FlutterSdk sdk) {
if (path != null) {
return findDefinition(className, iconName, project, path);
}
Expand All @@ -236,7 +263,7 @@ private IconInfo findStandardDefinition(@NotNull String className, @NotNull Stri
}

@Nullable
private Icon findStandardIconFromDef(@NotNull String name, @NotNull IconInfo iconDef, @NotNull String path) {
private static Icon findStandardIconFromDef(@NotNull String name, @NotNull IconInfo iconDef, @NotNull String path) {
assert LocalFileSystem.getInstance() != null;
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
if (virtualFile == null) return null;
Expand All @@ -246,7 +273,11 @@ private Icon findStandardIconFromDef(@NotNull String name, @NotNull IconInfo ico

// Note: package flutter_icons is not currently supported because it takes forever to analyze it.
@Nullable
private Icon getIconFromPackage(@Nullable PsiElement aPackage, @Nullable String family, @NotNull String argument, @NotNull Project project, @NotNull FlutterSdk sdk) {
private static Icon getIconFromPackage(@Nullable PsiElement aPackage,
@Nullable String family,
@NotNull String argument,
@NotNull Project project,
@NotNull FlutterSdk sdk) {
final int code;
try {
code = parseLiteralNumber(argument);
Expand All @@ -257,16 +288,17 @@ private Icon getIconFromPackage(@Nullable PsiElement aPackage, @Nullable String
family = family == null ? "MaterialIcons" : family;
if (aPackage == null) {
// Looking for IconData with no package -- package specification not currently supported.
final String relativeAssetPath = family.equals("MaterialIcons") ? MaterialRelativeAssetPath : CupertinoRelativeAssetPath;
// TODO Base path is wrong for cupertino -- is there a test for this branch (IconData with cupertino family)?
final IconPreviewGenerator generator = new IconPreviewGenerator(sdk.getHomePath() + relativeAssetPath);
final String assetPath = family.equals("MaterialIcons")
? sdk.getHomePath() + MaterialRelativeAssetPath
: FlutterSdkUtil.getPathToCupertinoIconsPackage(project) + CupertinoRelativeAssetPath;
final IconPreviewGenerator generator = new IconPreviewGenerator(assetPath);
return generator.convert(code);
}
return null;
}

@Nullable
private LineMarkerInfo<PsiElement> createLineMarker(@Nullable PsiElement element, @NotNull Icon icon) {
private static LineMarkerInfo<PsiElement> createLineMarker(@Nullable PsiElement element, @NotNull Icon icon) {
if (element == null) return null;
assert element.getTextRange() != null;
//noinspection MissingRecentApi
Expand All @@ -275,7 +307,10 @@ private LineMarkerInfo<PsiElement> createLineMarker(@Nullable PsiElement element
}

@Nullable
private IconInfo findDefinition(@NotNull String className, @NotNull String iconName, @NotNull Project project, @NotNull String path) {
private static IconInfo findDefinition(@NotNull String className,
@NotNull String iconName,
@NotNull Project project,
@NotNull String path) {
assert LocalFileSystem.getInstance() != null;
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
if (virtualFile == null) return null;
Expand All @@ -289,7 +324,7 @@ private IconInfo findDefinition(@NotNull String className, @NotNull String iconN
}

@Nullable
private Icon findIconFromDef(@NotNull String iconClassName, @NotNull IconInfo iconDef, @NotNull String path) {
private static Icon findIconFromDef(@NotNull String iconClassName, @NotNull IconInfo iconDef, @NotNull String path) {
assert LocalFileSystem.getInstance() != null;
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(path);
if (virtualFile == null) return null;
Expand Down Expand Up @@ -342,7 +377,7 @@ public boolean visitFile(@NotNull VirtualFile file) {
return null;
}

public double findPattern(@NotNull String t, @NotNull String p) {
public static double findPattern(@NotNull String t, @NotNull String p) {
// This is from https://github.com/tdebatty/java-string-similarity
// It's MIT license file is: https://github.com/tdebatty/java-string-similarity/blob/master/LICENSE.md
final JaroWinkler jw = new JaroWinkler();
Expand Down
17 changes: 17 additions & 0 deletions src/io/flutter/utils/UIUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.editor.colors.ColorKey;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -34,4 +37,18 @@ public static JComponent getComponentOfActionEvent(@NotNull AnActionEvent e) {
public static ColorKey getEditorNotificationBackgroundColor() {
return EditorColors.GUTTER_BACKGROUND;
}

@Nullable
public static Project findVisibleProject() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is a bit terrifying. At minimum add a comment that this needs to only be used from the deprecated Flutter IntelliJ inspector.
Ideally, flow the project into that renderer rather than having to guess it like this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I share your concern. I'll add a comment in my next PR.

final WindowManager wm = WindowManager.getInstance();
if (wm == null) return null;
final JFrame jframe = wm.findVisibleFrame();
if (jframe == null) return null;
for (IdeFrame frame : wm.getAllProjectFrames()) {
if (frame.getComponent() == jframe.getRootPane()) {
return frame.getProject();
}
}
return null;
}
}
5 changes: 3 additions & 2 deletions src/io/flutter/view/DiagnosticsTreeCellRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.speedSearch.SpeedSearchSupply;
import com.intellij.util.ui.UIUtil;
import io.flutter.editor.FlutterMaterialIcons;
import io.flutter.editor.FlutterIconLineMarkerProvider;
import io.flutter.inspector.DiagnosticLevel;
import io.flutter.inspector.DiagnosticsNode;
import io.flutter.utils.ColorIconMaker;
import io.flutter.utils.UIUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;

Expand Down Expand Up @@ -154,7 +155,7 @@ else if (isLinkedChild || panel.currentShowNode == value) {
case "IconData": {
final int codePoint = getIntMember(properties, "codePoint");
if (codePoint > 0) {
final Icon icon = FlutterMaterialIcons.getIconForHex(String.format("%1$04x", codePoint));
final Icon icon = FlutterIconLineMarkerProvider.getMaterialIconFromCodepoint(UIUtils.findVisibleProject(), codePoint);
if (icon != null) {
this.addIcon(icon);
this.setIconOpaque(false);
Expand Down
5 changes: 4 additions & 1 deletion src/io/flutter/view/InspectorPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.intellij.xdebugger.XSourcePosition;
import io.flutter.FlutterBundle;
import io.flutter.FlutterUtils;
import io.flutter.editor.FlutterIconLineMarkerProvider;
import io.flutter.editor.FlutterMaterialIcons;
import io.flutter.inspector.*;
import io.flutter.run.daemon.FlutterApp;
Expand Down Expand Up @@ -52,6 +53,8 @@
import java.util.*;
import java.util.concurrent.CompletableFuture;

import static io.flutter.utils.UIUtils.findVisibleProject;

public class InspectorPanel extends JPanel implements Disposable, InspectorService.InspectorServiceClient, InspectorTabPanel {
/**
* Maximum frame rate to refresh the inspector panel at to avoid taxing the
Expand Down Expand Up @@ -1345,7 +1348,7 @@ protected void customizeCellRenderer(JTable table, @Nullable Object value, boole
// IconData(U+0E88F)
final int codePoint = getIntProperty(properties, "codePoint");
if (codePoint > 0) {
final Icon icon = FlutterMaterialIcons.getIconForHex(String.format("%1$04x", codePoint));
final Icon icon = FlutterIconLineMarkerProvider.getMaterialIconFromCodepoint(UIUtils.findVisibleProject(), codePoint);
if (icon != null) {
this.setIcon(icon);
this.setIconOpaque(false);
Expand Down