From 9d63af0a142cd9ff77e1ec253e83af6cb9ea45ed Mon Sep 17 00:00:00 2001 From: crschnick Date: Sun, 21 Dec 2025 05:56:31 +0000 Subject: [PATCH] Various android fixes --- .../app/browser/BrowserSessionTabsComp.java | 20 +++++----- .../app/browser/file/BrowserDialogs.java | 2 +- .../browser/file/BrowserFileListNameCell.java | 4 +- .../app/browser/file/BrowserNavBarComp.java | 9 +---- .../file/BrowserQuickAccessContextMenu.java | 3 +- .../io/xpipe/app/comp/base/ChoiceComp.java | 4 +- .../xpipe/app/comp/base/ChoicePaneComp.java | 4 +- .../app/comp/base/IntComboFieldComp.java | 4 +- .../xpipe/app/ext/ShellDialectChoiceComp.java | 3 +- .../xpipe/app/hub/comp/StoreCategoryComp.java | 5 +-- .../app/hub/comp/StoreComboChoiceComp.java | 2 + .../io/xpipe/app/hub/comp/StoreEntryComp.java | 6 +-- .../hub/comp/StoreEntryListBatchBarComp.java | 4 +- .../app/hub/comp/StoreProviderChoiceComp.java | 4 +- .../hub/comp/StoreQuickAccessButtonComp.java | 6 +-- ...ContextMenuHelper.java => MenuHelper.java} | 38 +++++++++++++++---- .../xpipe/app/update/AppDistributionType.java | 9 ++++- build.gradle | 1 + .../ext/base/host/HostAddressChoiceComp.java | 2 + .../ext/base/identity/IdentitySelectComp.java | 2 + lang/strings/fixed_en.properties | 1 + 21 files changed, 86 insertions(+), 47 deletions(-) rename app/src/main/java/io/xpipe/app/platform/{ContextMenuHelper.java => MenuHelper.java} (56%) diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java index 308e95699..36bbb1c3c 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserSessionTabsComp.java @@ -8,7 +8,7 @@ import io.xpipe.app.comp.base.StackComp; import io.xpipe.app.core.App; import io.xpipe.app.core.AppFontSizes; import io.xpipe.app.core.AppI18n; -import io.xpipe.app.platform.ContextMenuHelper; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.LabelGraphic; import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.prefs.AppPrefs; @@ -295,10 +295,10 @@ public class BrowserSessionTabsComp extends SimpleComp { } private ContextMenu createContextMenu(TabPane tabs, Tab tab, BrowserSessionTab tabModel) { - var cm = ContextMenuHelper.create(); + var cm = MenuHelper.createContextMenu(); if (tabModel.isCloseable()) { - var unpin = ContextMenuHelper.item(LabelGraphic.none(), "unpinTab"); + var unpin = MenuHelper.createMenuItem(LabelGraphic.none(), "unpinTab"); unpin.visibleProperty() .bind(PlatformThread.sync(Bindings.createBooleanBinding( () -> { @@ -312,7 +312,7 @@ public class BrowserSessionTabsComp extends SimpleComp { }); cm.getItems().add(unpin); - var pin = ContextMenuHelper.item(LabelGraphic.none(), "pinTab"); + var pin = MenuHelper.createMenuItem(LabelGraphic.none(), "pinTab"); pin.visibleProperty() .bind(PlatformThread.sync(Bindings.createBooleanBinding( () -> { @@ -326,7 +326,7 @@ public class BrowserSessionTabsComp extends SimpleComp { cm.getItems().add(pin); } - var select = ContextMenuHelper.item(LabelGraphic.none(), "selectTab"); + var select = MenuHelper.createMenuItem(LabelGraphic.none(), "selectTab"); select.acceleratorProperty() .bind(Bindings.createObjectBinding( () -> { @@ -347,7 +347,7 @@ public class BrowserSessionTabsComp extends SimpleComp { cm.getItems().add(new SeparatorMenuItem()); - var close = ContextMenuHelper.item(LabelGraphic.none(), "closeTab"); + var close = MenuHelper.createMenuItem(LabelGraphic.none(), "closeTab"); close.setAccelerator(new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN)); close.setOnAction(event -> { if (tab.isClosable()) { @@ -357,7 +357,7 @@ public class BrowserSessionTabsComp extends SimpleComp { }); cm.getItems().add(close); - var closeOthers = ContextMenuHelper.item(LabelGraphic.none(), "closeOtherTabs"); + var closeOthers = MenuHelper.createMenuItem(LabelGraphic.none(), "closeOtherTabs"); closeOthers.setOnAction(event -> { tabs.getTabs() .removeAll(tabs.getTabs().stream() @@ -367,7 +367,7 @@ public class BrowserSessionTabsComp extends SimpleComp { }); cm.getItems().add(closeOthers); - var closeLeft = ContextMenuHelper.item(LabelGraphic.none(), "closeLeftTabs"); + var closeLeft = MenuHelper.createMenuItem(LabelGraphic.none(), "closeLeftTabs"); closeLeft.setOnAction(event -> { var index = tabs.getTabs().indexOf(tab); tabs.getTabs() @@ -378,7 +378,7 @@ public class BrowserSessionTabsComp extends SimpleComp { }); cm.getItems().add(closeLeft); - var closeRight = ContextMenuHelper.item(LabelGraphic.none(), "closeRightTabs"); + var closeRight = MenuHelper.createMenuItem(LabelGraphic.none(), "closeRightTabs"); closeRight.setOnAction(event -> { var index = tabs.getTabs().indexOf(tab); tabs.getTabs() @@ -389,7 +389,7 @@ public class BrowserSessionTabsComp extends SimpleComp { }); cm.getItems().add(closeRight); - var closeAll = ContextMenuHelper.item(LabelGraphic.none(), "closeAllTabs"); + var closeAll = MenuHelper.createMenuItem(LabelGraphic.none(), "closeAllTabs"); closeAll.setAccelerator( new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN)); closeAll.setOnAction(event -> { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserDialogs.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserDialogs.java index 2689c67f2..a70f0e648 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserDialogs.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserDialogs.java @@ -13,7 +13,7 @@ public class BrowserDialogs { public static FileConflictChoice showFileConflictDialog(FilePath file, boolean multiple) { var choice = new SimpleObjectProperty(); var key = multiple ? "fileConflictAlertContentMultiple" : "fileConflictAlertContent"; - var w = multiple ? 1050 : 400; + var w = multiple ? 900 : 400; var modal = ModalOverlay.of( "fileConflictAlertTitle", AppDialog.dialogText(AppI18n.observable(key, file)).prefWidth(w)); diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListNameCell.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListNameCell.java index 256fd6228..3ca5b9869 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListNameCell.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListNameCell.java @@ -3,7 +3,7 @@ package io.xpipe.app.browser.file; import io.xpipe.app.comp.base.LazyTextFieldComp; import io.xpipe.app.comp.base.PrettyImageHelper; import io.xpipe.app.ext.FileKind; -import io.xpipe.app.platform.ContextMenuHelper; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.InputHelper; import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.util.BooleanScope; @@ -132,7 +132,7 @@ class BrowserFileListNameCell extends TableCell { if (selected.size() > 0 && selected.getLast() == getTableRow().getItem()) { var cm = new BrowserContextMenu( fileList.getFileSystemModel(), getTableRow().getItem(), false); - ContextMenuHelper.toggleShow(cm, this, Side.RIGHT); + MenuHelper.toggleMenuShow(cm, this, Side.RIGHT); event.consume(); } }); diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserNavBarComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserNavBarComp.java index 2adefd3f2..baef1e4b3 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserNavBarComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserNavBarComp.java @@ -3,16 +3,12 @@ package io.xpipe.app.browser.file; import io.xpipe.app.browser.icon.BrowserIconManager; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.CompStructure; -import io.xpipe.app.comp.SimpleCompStructure; import io.xpipe.app.comp.augment.ContextMenuAugment; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.PrettyImageHelper; import io.xpipe.app.comp.base.TextFieldComp; -import io.xpipe.app.comp.base.TooltipHelper; -import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppFontSizes; -import io.xpipe.app.core.AppI18n; -import io.xpipe.app.platform.ContextMenuHelper; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.LabelGraphic; import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.util.BooleanScope; @@ -34,7 +30,6 @@ import javafx.scene.layout.StackPane; import javafx.scene.shape.Rectangle; import atlantafx.base.theme.Styles; -import org.kordamp.ikonli.javafx.FontIcon; public class BrowserNavBarComp extends Comp { @@ -194,7 +189,7 @@ public class BrowserNavBarComp extends Comp { } private ContextMenu createContextMenu() { - var cm = ContextMenuHelper.create(); + var cm = MenuHelper.createContextMenu(); var f = model.getHistory().getForwardHistory(8).stream().toList(); for (int i = f.size() - 1; i >= 0; i--) { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java index df5988d21..c864e018e 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java @@ -7,6 +7,7 @@ import io.xpipe.app.ext.FileEntry; import io.xpipe.app.ext.FileKind; import io.xpipe.app.platform.BooleanAnimationTimer; import io.xpipe.app.platform.InputHelper; +import io.xpipe.app.update.AppDistributionType; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.ThreadHelper; @@ -61,7 +62,7 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { hide(); e.consume(); }); - setAutoHide(true); + setAutoHide(AppDistributionType.get() != AppDistributionType.ANDROID_LINUX_TERMINAL); getStyleClass().add("condensed"); } diff --git a/app/src/main/java/io/xpipe/app/comp/base/ChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/base/ChoiceComp.java index 1b6e12665..ac42cd427 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ChoiceComp.java @@ -4,6 +4,7 @@ import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.CompStructure; import io.xpipe.app.comp.SimpleCompStructure; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.util.Translatable; @@ -12,6 +13,7 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.scene.control.ComboBox; +import javafx.scene.control.skin.ComboBoxListViewSkin; import javafx.util.StringConverter; import lombok.AccessLevel; @@ -45,7 +47,7 @@ public class ChoiceComp extends Comp>> { @Override public CompStructure> createBase() { - var cb = new ComboBox(); + var cb = MenuHelper.createComboBox(); cb.setConverter(new StringConverter<>() { @Override public String toString(T object) { diff --git a/app/src/main/java/io/xpipe/app/comp/base/ChoicePaneComp.java b/app/src/main/java/io/xpipe/app/comp/base/ChoicePaneComp.java index f112dc070..3e2f796cb 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ChoicePaneComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ChoicePaneComp.java @@ -3,6 +3,7 @@ package io.xpipe.app.comp.base; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.CompStructure; import io.xpipe.app.comp.SimpleCompStructure; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.PlatformThread; import javafx.beans.property.Property; @@ -35,7 +36,8 @@ public class ChoicePaneComp extends Comp> { @Override public CompStructure createBase() { var list = FXCollections.observableArrayList(entries); - var cb = new ComboBox<>(list); + var cb = MenuHelper.createComboBox(); + cb.setItems(list); cb.setOnKeyPressed(event -> { if (!cb.isShowing() && event.getCode().equals(KeyCode.ENTER)) { cb.show(); diff --git a/app/src/main/java/io/xpipe/app/comp/base/IntComboFieldComp.java b/app/src/main/java/io/xpipe/app/comp/base/IntComboFieldComp.java index 6a0d078bf..5a65ab5e0 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/IntComboFieldComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/IntComboFieldComp.java @@ -3,6 +3,7 @@ package io.xpipe.app.comp.base; import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.CompStructure; import io.xpipe.app.comp.SimpleCompStructure; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.PlatformThread; import javafx.beans.property.Property; @@ -32,14 +33,13 @@ public class IntComboFieldComp extends Comp>> { @Override public CompStructure> createBase() { - var text = new ComboBox(); + var text = MenuHelper.createComboBox(); text.setEditable(true); text.setValue(value.getValue() != null ? value.getValue().toString() : null); text.setItems(FXCollections.observableList( predefined.stream().map(integer -> "" + integer).toList())); text.setMaxWidth(20000); text.getStyleClass().add("int-combo-field-comp"); - text.setSkin(new ComboBoxListViewSkin<>(text)); text.setVisibleRowCount(Math.min(10, predefined.size())); value.addListener((ChangeListener) (observableValue, oldValue, newValue) -> { diff --git a/app/src/main/java/io/xpipe/app/ext/ShellDialectChoiceComp.java b/app/src/main/java/io/xpipe/app/ext/ShellDialectChoiceComp.java index fec44d5f0..b37392576 100644 --- a/app/src/main/java/io/xpipe/app/ext/ShellDialectChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/ext/ShellDialectChoiceComp.java @@ -3,6 +3,7 @@ package io.xpipe.app.ext; import io.xpipe.app.comp.SimpleComp; import io.xpipe.app.comp.base.PrettyImageHelper; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.process.ShellDialect; import io.xpipe.app.process.ShellDialects; @@ -76,7 +77,7 @@ public class ShellDialectChoiceComp extends SimpleComp { .createRegion()); } }; - var cb = new ComboBox(); + var cb = MenuHelper.createComboBox(); cb.setCellFactory(param -> supplier.get()); cb.setButtonCell(supplier.get()); cb.setValue(selected.getValue()); diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreCategoryComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreCategoryComp.java index 7c62d2998..197c222af 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreCategoryComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreCategoryComp.java @@ -1,14 +1,13 @@ package io.xpipe.app.hub.comp; import io.xpipe.app.comp.Comp; -import io.xpipe.app.comp.CompDescriptor; import io.xpipe.app.comp.SimpleComp; import io.xpipe.app.comp.augment.ContextMenuAugment; import io.xpipe.app.comp.base.*; import io.xpipe.app.core.AppFontSizes; import io.xpipe.app.core.AppI18n; import io.xpipe.app.platform.ClipboardHelper; -import io.xpipe.app.platform.ContextMenuHelper; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.LabelGraphic; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; @@ -199,7 +198,7 @@ public class StoreCategoryComp extends SimpleComp { } private ContextMenu createContextMenu(Region text) { - var contextMenu = ContextMenuHelper.create(); + var contextMenu = MenuHelper.createContextMenu(); if (AppPrefs.get().enableHttpApi().get()) { var copyId = new MenuItem(AppI18n.get("copyId"), new FontIcon("mdi2c-content-copy")); diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreComboChoiceComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreComboChoiceComp.java index bfe2646e9..d11125154 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreComboChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreComboChoiceComp.java @@ -3,6 +3,7 @@ package io.xpipe.app.hub.comp; import io.xpipe.app.comp.SimpleComp; import io.xpipe.app.ext.DataStore; import io.xpipe.app.issue.TrackEvent; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.storage.DataStoreEntryRef; @@ -119,6 +120,7 @@ public class StoreComboChoiceComp extends SimpleComp { } }; combo.setSkin(skin); + MenuHelper.fixComboBoxSkin(skin); combo.setMaxWidth(20000); combo.setEditable(true); diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java index 707c9e9cc..19131d7fd 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryComp.java @@ -353,7 +353,7 @@ public abstract class StoreEntryComp extends SimpleComp { if (branch != null) { button.apply(new ContextMenuAugment<>( mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, keyEvent -> false, () -> { - var cm = ContextMenuHelper.create(); + var cm = MenuHelper.createContextMenu(); var children = branch.getChildren(getWrapper().getEntry().ref()); var cats = Arrays.stream(StoreActionCategory.values()) @@ -416,7 +416,7 @@ public abstract class StoreEntryComp extends SimpleComp { } protected ContextMenu createContextMenu(Region name) { - var contextMenu = ContextMenuHelper.create(); + var contextMenu = MenuHelper.createContextMenu(); handleContextMenuCount(contextMenu); var cats = Arrays.stream(StoreActionCategory.values()).collect(Collectors.toCollection(ArrayList::new)); @@ -537,7 +537,7 @@ public abstract class StoreEntryComp extends SimpleComp { } var index = - ContextMenuHelper.item(new LabelGraphic.IconGraphic("mdi2t-tag-plus-outline"), "createTag"); + MenuHelper.createMenuItem(new LabelGraphic.IconGraphic("mdi2t-tag-plus-outline"), "createTag"); index.setOnAction(event -> { var tagName = new SimpleStringProperty(); var modal = ModalOverlay.of( diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryListBatchBarComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryListBatchBarComp.java index f4212342a..f54448c05 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryListBatchBarComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreEntryListBatchBarComp.java @@ -8,7 +8,7 @@ import io.xpipe.app.comp.base.*; import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.DataStore; import io.xpipe.app.hub.action.BatchHubProvider; -import io.xpipe.app.platform.ContextMenuHelper; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.DerivedObservableList; import io.xpipe.app.storage.DataStoreEntryRef; @@ -145,7 +145,7 @@ public class StoreEntryListBatchBarComp extends SimpleComp { if (batchActions.size() > 0) { button.apply(new ContextMenuAugment<>( mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, keyEvent -> false, () -> { - var cm = ContextMenuHelper.create(); + var cm = MenuHelper.createContextMenu(); s.getChildren(childrenRefs.getList()).forEach(childProvider -> { var menu = buildMenuItemForAction(childrenRefs.getList(), childProvider); cm.getItems().add(menu); diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreProviderChoiceComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreProviderChoiceComp.java index 8cdd8e4a2..937b1919e 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreProviderChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreProviderChoiceComp.java @@ -8,6 +8,8 @@ import io.xpipe.app.ext.DataStoreProvider; import io.xpipe.app.ext.DataStoreProviders; import io.xpipe.app.platform.JfxHelper; +import io.xpipe.app.platform.MenuHelper; +import io.xpipe.app.process.ShellDialect; import javafx.beans.property.Property; import javafx.scene.control.ComboBox; import javafx.scene.control.ListCell; @@ -60,7 +62,7 @@ public class StoreProviderChoiceComp extends Comp(); + var cb = MenuHelper.createComboBox(); cb.setCellFactory(param -> { return cellFactory.get(); }); diff --git a/app/src/main/java/io/xpipe/app/hub/comp/StoreQuickAccessButtonComp.java b/app/src/main/java/io/xpipe/app/hub/comp/StoreQuickAccessButtonComp.java index 2d8c01f3f..045c594a9 100644 --- a/app/src/main/java/io/xpipe/app/hub/comp/StoreQuickAccessButtonComp.java +++ b/app/src/main/java/io/xpipe/app/hub/comp/StoreQuickAccessButtonComp.java @@ -4,7 +4,7 @@ import io.xpipe.app.comp.Comp; import io.xpipe.app.comp.CompStructure; import io.xpipe.app.comp.base.IconButtonComp; import io.xpipe.app.comp.base.PrettyImageHelper; -import io.xpipe.app.platform.ContextMenuHelper; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.LabelGraphic; import javafx.geometry.Side; @@ -32,7 +32,7 @@ public class StoreQuickAccessButtonComp extends Comp> { return null; } - var cm = ContextMenuHelper.create(); + var cm = MenuHelper.createContextMenu(); cm.getStyleClass().add("condensed"); Menu menu = (Menu) recurse(cm, section); cm.getItems().addAll(menu.getItems()); @@ -94,7 +94,7 @@ public class StoreQuickAccessButtonComp extends Comp> { return; } - ContextMenuHelper.toggleShow(menu.get(), struc.get(), Side.RIGHT); + MenuHelper.toggleMenuShow(menu.get(), struc.get(), Side.RIGHT); event.consume(); }); }); diff --git a/app/src/main/java/io/xpipe/app/platform/ContextMenuHelper.java b/app/src/main/java/io/xpipe/app/platform/MenuHelper.java similarity index 56% rename from app/src/main/java/io/xpipe/app/platform/ContextMenuHelper.java rename to app/src/main/java/io/xpipe/app/platform/MenuHelper.java index 36967e149..ce205cc4d 100644 --- a/app/src/main/java/io/xpipe/app/platform/ContextMenuHelper.java +++ b/app/src/main/java/io/xpipe/app/platform/MenuHelper.java @@ -3,19 +3,41 @@ package io.xpipe.app.platform; import io.xpipe.app.core.AppFontSizes; import io.xpipe.app.core.AppI18n; +import io.xpipe.app.update.AppDistributionType; import javafx.application.Platform; import javafx.geometry.Side; import javafx.scene.Node; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; +import javafx.scene.control.*; +import javafx.scene.control.skin.ComboBoxListViewSkin; +import javafx.scene.control.skin.ComboBoxPopupControl; import javafx.scene.layout.Region; +import lombok.SneakyThrows; -public class ContextMenuHelper { +import java.util.function.Function; - public static ContextMenu create() { +public class MenuHelper { + + @SneakyThrows + public static ComboBoxListViewSkin fixComboBoxSkin(ComboBoxListViewSkin skin) { + var m = ComboBoxPopupControl.class.getDeclaredMethod("getPopup"); + m.setAccessible(true); + var popup = (PopupControl) m.invoke(skin); + popup.setAutoHide(AppDistributionType.get() != AppDistributionType.ANDROID_LINUX_TERMINAL); + return skin; + } + + @SneakyThrows + public static ComboBox createComboBox() { + var cb = new ComboBox(); + var skin = new ComboBoxListViewSkin<>(cb); + fixComboBoxSkin(skin); + cb.setSkin(skin); + return cb; + } + + public static ContextMenu createContextMenu() { ContextMenu contextMenu = new ContextMenu(); - contextMenu.setAutoHide(true); + contextMenu.setAutoHide(AppDistributionType.get() != AppDistributionType.ANDROID_LINUX_TERMINAL); InputHelper.onLeft(contextMenu, false, e -> { contextMenu.hide(); e.consume(); @@ -41,14 +63,14 @@ public class ContextMenuHelper { return contextMenu; } - public static MenuItem item(LabelGraphic graphic, String nameKey) { + public static MenuItem createMenuItem(LabelGraphic graphic, String nameKey) { var i = new MenuItem(); i.textProperty().bind(AppI18n.observable(nameKey)); i.setGraphic(graphic.createGraphicNode()); return i; } - public static void toggleShow(ContextMenu contextMenu, Node ref, Side side) { + public static void toggleMenuShow(ContextMenu contextMenu, Node ref, Side side) { if (!contextMenu.isShowing()) { // Prevent NPE in show() if (contextMenu.getScene() == null || ref == null || ref.getScene() == null) { diff --git a/app/src/main/java/io/xpipe/app/update/AppDistributionType.java b/app/src/main/java/io/xpipe/app/update/AppDistributionType.java index ddb46b3ee..d807aae3e 100644 --- a/app/src/main/java/io/xpipe/app/update/AppDistributionType.java +++ b/app/src/main/java/io/xpipe/app/update/AppDistributionType.java @@ -56,7 +56,7 @@ public enum AppDistributionType implements Translatable { CHOCO("choco", true, () -> new ChocoUpdater()), WINGET("winget", true, () -> new WingetUpdater()), SCOOP("scoop", false, () -> new PortableUpdater(true)), - ; + ANDROID_LINUX_TERMINAL("androidLinuxTerminal", false, () -> new PortableUpdater(true)); private static AppDistributionType type; @@ -152,6 +152,13 @@ public enum AppDistributionType implements Translatable { return PORTABLE; } } else { + if (OsType.ofLocal() == OsType.LINUX) { + var uname = LocalExec.readStdoutIfPossible("uname", "-a"); + if (uname.isPresent() && uname.get().contains("android") && uname.get().contains("aarch64")) { + return ANDROID_LINUX_TERMINAL; + } + } + var file = base.resolve("installation"); if (!Files.exists(file)) { if (OsType.ofLocal() == OsType.LINUX && Files.exists(base.resolve("aur"))) { diff --git a/build.gradle b/build.gradle index 82dcc7a94..1ceaed204 100644 --- a/build.gradle +++ b/build.gradle @@ -141,6 +141,7 @@ def getJvmArgs() { "--add-exports", "jdk.zipfs/jdk.nio.zipfs=io.xpipe.modulefs", "--add-opens", "javafx.graphics/com.sun.glass.ui=$appPackage", "--add-opens", "javafx.graphics/javafx.stage=$appPackage", + "--add-opens", "javafx.controls/javafx.scene.control.skin=$appPackage", "--add-opens", "javafx.graphics/com.sun.javafx.tk=$appPackage", "--add-opens", "javafx.graphics/com.sun.javafx.tk.quantum=$appPackage" ] diff --git a/ext/base/src/main/java/io/xpipe/ext/base/host/HostAddressChoiceComp.java b/ext/base/src/main/java/io/xpipe/ext/base/host/HostAddressChoiceComp.java index 82758ed99..1096b17d5 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/host/HostAddressChoiceComp.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/host/HostAddressChoiceComp.java @@ -5,6 +5,7 @@ import io.xpipe.app.comp.CompStructure; import io.xpipe.app.comp.SimpleCompStructure; import io.xpipe.app.comp.base.*; +import io.xpipe.app.platform.MenuHelper; import javafx.application.Platform; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -131,6 +132,7 @@ public class HostAddressChoiceComp extends Comp> { }); combo.apply(struc -> { var skin = new ComboBoxListViewSkin<>(struc.get()); + MenuHelper.fixComboBoxSkin(skin); struc.get().setSkin(skin); skin.setHideOnClick(false); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/identity/IdentitySelectComp.java b/ext/base/src/main/java/io/xpipe/ext/base/identity/IdentitySelectComp.java index e098e0b4b..8e9e70acd 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/identity/IdentitySelectComp.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/identity/IdentitySelectComp.java @@ -9,6 +9,7 @@ import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.DataStoreCreationCategory; import io.xpipe.app.hub.comp.*; import io.xpipe.app.platform.LabelGraphic; +import io.xpipe.app.platform.MenuHelper; import io.xpipe.app.platform.PlatformThread; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.secret.EncryptedValue; @@ -324,6 +325,7 @@ public class IdentitySelectComp extends Comp> { popover.hide(); } }; + MenuHelper.fixComboBoxSkin(skin); struc.get().setSkin(skin); }); diff --git a/lang/strings/fixed_en.properties b/lang/strings/fixed_en.properties index 8f45b1852..a625a8934 100644 --- a/lang/strings/fixed_en.properties +++ b/lang/strings/fixed_en.properties @@ -154,3 +154,4 @@ rsa=RSA ed25519=ED25519 ed25519Sk=ED25519 (FIDO2) westonEditor=Weston Editor +androidLinuxTerminalDist=Android Linux Terminal