diff --git a/CHANGELOG.md b/CHANGELOG.md index 653c945e2..0f9904c3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Set the device selector component to opaque during its creation to avoid an unexpected background color (#8471) - Refactored `DeviceSelectorAction` and add rich icons to different platform devices (#8475) - Fix DTD freezes when opening projects, and EDT freezes when the theme is changed and opening embedded DevTools (#8477) +- Fix `DeviceSelectorAction` `NoSuchElementException` in the toolbar layout (#8515) ## 87.1.0 diff --git a/src/io/flutter/FlutterBundle.properties b/src/io/flutter/FlutterBundle.properties index f2808e30d..27ea5211c 100644 --- a/src/io/flutter/FlutterBundle.properties +++ b/src/io/flutter/FlutterBundle.properties @@ -74,6 +74,8 @@ flutter.io.gettingStarted.IDE.url=https://docs.flutter.dev/tools/android-studio flutter.io.runAndDebug.url=https://docs.flutter.dev/tools/android-studio#running-and-debugging devicelist.loading=Loading... +devicelist.noDevices= +devicelist.noDeviceSelected= flutter.pop.frame.action.text=Drop Frame (Flutter) flutter.pop.frame.action.description=Pop the current frame off the stack diff --git a/src/io/flutter/actions/DeviceSelectorAction.java b/src/io/flutter/actions/DeviceSelectorAction.java index c2c23728b..96e8b8a32 100644 --- a/src/io/flutter/actions/DeviceSelectorAction.java +++ b/src/io/flutter/actions/DeviceSelectorAction.java @@ -47,6 +47,8 @@ public class DeviceSelectorAction extends AnAction implements CustomComponentAct private static final Key ICON_LABEL_KEY = Key.create("iconLabel"); private static final Key TEXT_LABEL_KEY = Key.create("textLabel"); private static final Key ARROW_LABEL_KEY = Key.create("arrowLabel"); + private static final @NotNull Icon DEFAULT_DEVICE_ICON = FlutterIcons.Mobile; + private static final @NotNull Icon DEFAULT_ARROW_ICON = IconUtil.scale(AllIcons.General.ChevronDown, null, 1.2f); private final List actions = new ArrayList(); private final List knownProjects = Collections.synchronizedList(new ArrayList()); @@ -87,9 +89,9 @@ public void actionPerformed(@NotNull AnActionEvent e) { @Override public @NotNull JComponent createCustomComponent(@NotNull Presentation presentation, @NotNull String place) { - final JBLabel iconLabel = new JBLabel(FlutterIcons.Mobile); + final JBLabel iconLabel = new JBLabel(DEFAULT_DEVICE_ICON); final JBLabel textLabel = new JBLabel(); - final JBLabel arrowLabel = new JBLabel(IconUtil.scale(AllIcons.General.ChevronDown, null, 1.2f)); + final JBLabel arrowLabel = new JBLabel(DEFAULT_ARROW_ICON); // Create a wrapper button for hover effects final JButton button = new JButton() { @@ -119,10 +121,26 @@ public Dimension getPreferredSize() { width += icon.getIconWidth(); height = Math.max(height, icon.getIconHeight()); } + else { + // Fallback: use the default mobile icon size when the component is not fully initialized + final Icon defaultIcon = DEFAULT_DEVICE_ICON; + width += defaultIcon.getIconWidth(); + height = Math.max(height, defaultIcon.getIconHeight()); + } + final @Nullable FontMetrics fm; + final @NotNull String textLabelText; if (textLabel instanceof JBLabel label && label.getText() instanceof String text && !text.isEmpty()) { - final FontMetrics fm = label.getFontMetrics(label.getFont()); - width += Objects.requireNonNull(fm).stringWidth(text); + fm = label.getFontMetrics(label.getFont()); + textLabelText = text; + } + else { + // Fallback: estimate width for typical device name length + fm = getFontMetrics(getFont()); + textLabelText = FlutterBundle.message("devicelist.noDevices"); + } + if (fm != null) { + width += fm.stringWidth(textLabelText); height = Math.max(height, fm.getHeight()); } @@ -130,6 +148,12 @@ public Dimension getPreferredSize() { width += icon.getIconWidth(); height = Math.max(height, icon.getIconHeight()); } + else { + // Fallback: use the default arrow icon size + final Icon defaultArrow = DEFAULT_ARROW_ICON; + width += defaultArrow.getIconWidth(); + height = Math.max(height, defaultArrow.getIconHeight()); + } width += JBUI.scale(24); height += JBUI.scale(8); @@ -278,7 +302,7 @@ public void projectClosing(@NotNull Project project) { final Collection devices = deviceService.getConnectedDevices(); final String text; - Icon icon = FlutterIcons.Mobile; + Icon icon = DEFAULT_DEVICE_ICON; if (devices.isEmpty()) { final boolean isLoading = deviceService.getStatus() == DeviceService.State.LOADING; @@ -286,11 +310,11 @@ public void projectClosing(@NotNull Project project) { text = FlutterBundle.message("devicelist.loading"); } else { - text = ""; + text = FlutterBundle.message("devicelist.noDevices"); } } else if (selectedDevice == null) { - text = ""; + text = FlutterBundle.message("devicelist.noDeviceSelected"); } else { text = selectedDevice.presentationName();

AltStyle によって変換されたページ (->オリジナル) /