From d5bcad3ddc03f75c029fca04613bd4ee8ba66800 Mon Sep 17 00:00:00 2001 From: Satya Date: Sat, 22 Aug 2026 10:07:40 +0800 Subject: [PATCH 1/2] Show the build's version in Settings > About MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first question on any bug report is "which build?", and until now a user had no way to answer it: no window title, no menu, and a native binary that reports nothing. With four pre-releases out and casks installing a fifth, "the latest one" is not an answer. Settings now ends with an About card carrying the wallet version, the pinned Yano node version, and the runtime, plus a button that copies all of it together with the OS for pasting into an issue. The values are GENERATED from gradle.properties at build time, never edited by hand — a constant is wrong the moment someone forgets to bump it, which is exactly when a version display does the most damage. Generated as Java source rather than a properties resource: native-image includes only resources that are explicitly registered, so a resource would work in the jar build and silently come back null in the native one — missing where it is hardest to notice. The runtime line distinguishes a native image from a JVM instead of printing a Java version the native build does not have. That distinction has already mattered: several bugs this month reproduced only under native-image. Verified the value tracks its source by building with walletVersion set to 9.9.9-test and back. Co-Authored-By: Claude Opus 5 (1M context) --- wallet-ui/build.gradle | 47 +++++++++++++++ .../wallet/ui/screens/SettingsScreen.java | 60 ++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/wallet-ui/build.gradle b/wallet-ui/build.gradle index ec3d645..ae4765d 100644 --- a/wallet-ui/build.gradle +++ b/wallet-ui/build.gradle @@ -27,6 +27,53 @@ test { useJUnitPlatform() } +// The version shown in Settings > About comes from gradle.properties at BUILD +// time. A hand-edited constant is wrong the moment someone forgets to bump it, +// and the version is the first thing a bug report quotes. +// +// Generated as Java SOURCE, not a properties resource: native-image includes +// only resources that are explicitly registered, so a resource would work in the +// jar build and silently come back null in the native one — the version would be +// missing exactly where it is hardest to notice. +def buildInfoDir = layout.buildDirectory.dir('generated/sources/buildinfo') + +def generateBuildInfo = tasks.register('generateBuildInfo') { + description = 'Generate BuildInfo.java from gradle.properties' + def walletVersion = project.version.toString() + def nodeVersion = (rootProject.findProperty('yanoVersion') ?: 'unknown').toString() + def outDir = buildInfoDir + inputs.property('walletVersion', walletVersion) + inputs.property('nodeVersion', nodeVersion) + outputs.dir(outDir) + doLast { + def pkg = new File(outDir.get().asFile, 'com/bloxbean/cardano/yano/wallet/ui') + pkg.mkdirs() + new File(pkg, 'BuildInfo.java').text = """package com.bloxbean.cardano.yano.wallet.ui; + +/** + * Build-time facts, generated by :wallet-ui:generateBuildInfo from + * gradle.properties. Do not edit — your changes are overwritten on every build. + */ +public final class BuildInfo { + + /** The wallet's version, e.g. "0.1.0-pre4". */ + public static final String WALLET_VERSION = "${walletVersion}"; + + /** The managed Yano node this build is pinned to. */ + public static final String NODE_VERSION = "${nodeVersion}"; + + private BuildInfo() { + } +} +""" + } +} + +// Registering the provider (not the directory) makes compileJava depend on the +// generating task, so a plain `./gradlew build` cannot compile a stale copy. +sourceSets.main.java.srcDir generateBuildInfo + + def detectJavafxPlatform() { def osName = System.getProperty('os.name').toLowerCase() def osArch = System.getProperty('os.arch').toLowerCase() diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java index f9d292b..0b7939c 100644 --- a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java +++ b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java @@ -1,10 +1,12 @@ package com.bloxbean.cardano.yano.wallet.ui.screens; +import com.bloxbean.cardano.yano.wallet.ui.BuildInfo; import com.bloxbean.cardano.yano.wallet.ui.Shell; import com.bloxbean.cardano.yano.wallet.ui.contract.WalletUiController; import com.bloxbean.cardano.yano.wallet.ui.live.LivePrefs; import com.bloxbean.cardano.yano.wallet.ui.util.ThemeManager; import com.bloxbean.cardano.yano.wallet.ui.util.Ui; +import javafx.animation.PauseTransition; import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -22,7 +24,10 @@ import javafx.scene.layout.HBox; import javafx.scene.control.TextField; import javafx.scene.layout.StackPane; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; import javafx.scene.layout.VBox; +import javafx.util.Duration; import java.util.Arrays; import java.util.List; @@ -139,7 +144,7 @@ private ScrollPane build() { VBox advancedCard = Ui.card("Managed node", relaysPane, filesPane); VBox column = new VBox(16, title, appearanceCard(), nodeCard, walletCard, securityCard, - dappsCard, connectorCard, advancedCard); + dappsCard, connectorCard, advancedCard, aboutCard()); column.setPadding(new Insets(24)); column.setMaxWidth(860); ScrollPane scroll = new ScrollPane(column); @@ -278,6 +283,59 @@ public void refresh() { loadSecurityKey(); } + /** + * Versions, and a one-click copy of them. The first question on any bug + * report is "which build?", and a user cannot answer it from a window title + * or a binary that reports nothing. BuildInfo is generated from + * gradle.properties at build time, so this cannot drift from the release. + */ + private VBox aboutCard() { + Label version = new Label("Yano Wallet " + BuildInfo.WALLET_VERSION); + version.getStyleClass().add("mono"); + + Label node = new Label("Managed node: Yano " + BuildInfo.NODE_VERSION); + node.getStyleClass().add("mono"); + + Label runtime = new Label("Runtime: " + runtimeDescription()); + runtime.getStyleClass().add("mono"); + + Button copy = new Button("Copy version details"); + copy.getStyleClass().add("ghost-button"); + copy.setOnAction(e -> { + ClipboardContent content = new ClipboardContent(); + content.putString(versionReport()); + Clipboard.getSystemClipboard().setContent(content); + copy.setText("Copied"); + PauseTransition reset = new PauseTransition(Duration.seconds(1.5)); + reset.setOnFinished(done -> copy.setText("Copy version details")); + reset.play(); + }); + + return Ui.card("About", version, node, runtime, + Ui.muted("Paste these details into a bug report — they identify the exact " + + "build, which the wallet cannot infer from anything else."), + copy); + } + + /** + * Native images have no JVM to report, and saying "Java 25" there would be a + * lie that sends a bug report down the wrong path. + */ + private static String runtimeDescription() { + if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { + return "native image (no JVM)"; + } + return "Java " + Runtime.version().feature() + " (" + System.getProperty("java.vendor") + ")"; + } + + private static String versionReport() { + return "Yano Wallet " + BuildInfo.WALLET_VERSION + + "\nManaged node: Yano " + BuildInfo.NODE_VERSION + + "\nRuntime: " + runtimeDescription() + + "\nOS: " + System.getProperty("os.name") + " " + System.getProperty("os.version") + + " (" + System.getProperty("os.arch") + ")"; + } + private VBox appearanceCard() { ComboBox themePicker = new ComboBox<>(); ThemeManager.themes().forEach(theme -> themePicker.getItems().add(theme.label())); From 036d813663fb5225b0e406aa9923c56d09144c41 Mon Sep 17 00:00:00 2001 From: Satya Date: Sat, 22 Aug 2026 10:29:45 +0800 Subject: [PATCH 2/2] Make About a top-level screen; drop the animated live-chain background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes to the same screens, both for pre5. About moves out of Settings into its own sidebar entry after it. The version is what a bug report asks for first, and someone answering that should not have to guess it lives under Settings. The screen takes no controller — every value comes from BuildInfo, generated at build time — so it still renders when the node is down or the wallet is locked, which is exactly when someone is filing a bug. It also now reports the platform, since "which build?" is only half an answer without the machine, and reuses Ui.copyToClipboard/Ui.toast rather than the hand-rolled clipboard handling it had. The animated live-chain background is removed: it did not look good, and it had already been shipped opt-in and off by default, so removing it changes nothing anyone is currently seeing. Gone with it are LivePrefs, which existed only to store that one key, the ambient LiveBlocksView behind every screen, and its change listener. The Live page is untouched and keeps its own view. One behaviour change falls out: chain-tip polling used to run whenever the background was on OR the Live page was open, and now runs only for the Live page. Strictly less work, same behaviour where it is visible. LiveBlocksView keeps its now-unreachable ambient mode. Unpicking it means editing the drawing code the Live page depends on, for nothing a user can see; the class doc records why the flag survives. Co-Authored-By: Claude Opus 5 (1M context) --- .../cardano/yano/wallet/ui/Shell.java | 36 ++--- .../ui/contract/WalletUiController.java | 2 +- .../yano/wallet/ui/live/LiveBlocksView.java | 13 +- .../yano/wallet/ui/live/LivePrefs.java | 40 ------ .../yano/wallet/ui/screens/AboutScreen.java | 123 ++++++++++++++++++ .../wallet/ui/screens/SettingsScreen.java | 69 +--------- .../cardano/yano/wallet/ui/util/Icons.java | 3 + 7 files changed, 143 insertions(+), 143 deletions(-) delete mode 100644 wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LivePrefs.java create mode 100644 wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/AboutScreen.java diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/Shell.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/Shell.java index 6725315..b44390f 100644 --- a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/Shell.java +++ b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/Shell.java @@ -5,14 +5,13 @@ import com.bloxbean.cardano.yano.wallet.ui.screens.HistoryScreen; import com.bloxbean.cardano.yano.wallet.ui.screens.ReceiveScreen; import com.bloxbean.cardano.yano.wallet.ui.screens.SendScreen; +import com.bloxbean.cardano.yano.wallet.ui.screens.AboutScreen; import com.bloxbean.cardano.yano.wallet.ui.screens.SettingsScreen; import com.bloxbean.cardano.yano.wallet.ui.screens.GovernanceScreen; import com.bloxbean.cardano.yano.wallet.ui.screens.ProposalsScreen; import com.bloxbean.cardano.yano.wallet.ui.screens.LiveScreen; import com.bloxbean.cardano.yano.wallet.ui.screens.StakingScreen; -import com.bloxbean.cardano.yano.wallet.ui.live.LiveBlocksView; import com.bloxbean.cardano.yano.wallet.ui.live.LiveChainModel; -import com.bloxbean.cardano.yano.wallet.ui.live.LivePrefs; import com.bloxbean.cardano.yano.wallet.ui.util.Icons; import com.bloxbean.cardano.yano.wallet.ui.util.Ui; import javafx.animation.KeyFrame; @@ -64,7 +63,6 @@ public class Shell { private final Tooltip syncTooltip = new Tooltip(); private final Timeline statusPoller; private final LiveChainModel liveModel = new LiveChainModel(); - private LiveBlocksView ambient; private String active; // Delta tracking to tell "advancing" from "stalled" during catch-up without // any network-tip math: remember the highest block seen and when it last rose. @@ -110,6 +108,9 @@ public Shell(WalletUiController controller, Runnable onLock, registry.put("Proposals", () -> new ProposalsScreen(controller, overlay)); registry.put("Live", () -> new LiveScreen(controller, overlay, liveModel)); registry.put("Settings", () -> new SettingsScreen(controller, overlay, this::changeNetwork)); + // Takes no controller: build facts come from BuildInfo, generated at build + // time, so this screen works even when nothing else does. + registry.put("About", () -> new AboutScreen(overlay)); statusPoller = new Timeline(new KeyFrame(Duration.seconds(5), e -> tick())); statusPoller.setCycleCount(Timeline.INDEFINITE); @@ -119,14 +120,8 @@ public StackPane root() { BorderPane frame = new BorderPane(); frame.getStyleClass().add("shell"); frame.setLeft(buildSidebar()); - // Ambient live-chain background sits behind every screen; screens have - // transparent gaps, so it shows through without touching their styling. - ambient = new LiveBlocksView(liveModel, true); - StackPane center = new StackPane(ambient, content); - frame.setCenter(center); + frame.setCenter(content); overlay.getChildren().add(frame); - syncAmbient(); - LivePrefs.setOnChange(() -> javafx.application.Platform.runLater(this::syncAmbient)); navigate("Dashboard"); statusPoller.play(); pollStatus(); @@ -135,27 +130,11 @@ public StackPane root() { public void dispose() { statusPoller.stop(); - LivePrefs.setOnChange(null); - if (ambient != null) { - ambient.dispose(); - } - } - - /** Reflect the ambient-background toggle: show/hide + start/stop the animation. */ - private void syncAmbient() { - boolean on = LivePrefs.ambientEnabled(); - if (ambient != null) { - ambient.setVisible(on); - ambient.setManaged(on); - ambient.setActive(on); - } - if (on) { - pollLiveChain(); - } } + /** The Live page is the only thing that consumes chain-tip data now. */ private boolean liveNeeded() { - return LivePrefs.ambientEnabled() || "Live".equals(active); + return "Live".equals(active); } private void pollLiveChain() { @@ -216,6 +195,7 @@ private Node buildSidebar() { addNav(side, "Proposals", Icons.PROPOSALS); addNav(side, "Live", Icons.LIVE); addNav(side, "Settings", Icons.SETTINGS); + addNav(side, "About", Icons.ABOUT); Region grow = new Region(); VBox.setVgrow(grow, Priority.ALWAYS); diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/contract/WalletUiController.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/contract/WalletUiController.java index 2f6c2ee..64b18d8 100644 --- a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/contract/WalletUiController.java +++ b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/contract/WalletUiController.java @@ -99,7 +99,7 @@ public interface WalletUiController { String dataDir(); /** - * Live chain-tip snapshot for the animated "Live" view / ambient background. + * Live chain-tip snapshot for the animated "Live" view. * Best-effort: returns {@link LiveChainView#unreachable()} rather than throwing * when the node is unavailable, so the visualization degrades quietly. */ diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LiveBlocksView.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LiveBlocksView.java index 4eeaba6..8e0c3a7 100644 --- a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LiveBlocksView.java +++ b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LiveBlocksView.java @@ -22,13 +22,12 @@ /** * A Canvas that animates the chain tip as a train of block tiles sliding in from * the right — newest at the leading edge, older easing left, each tile brightening - * with its transaction count. Reused in two modes: {@code ambient} (dim, behind - * the shell content) and full (the dedicated Live page). + * with its transaction count. * - *

Runs an {@link AnimationTimer} only while it is {@link #setActive active}, - * attached to a scene, AND its window is focused — so it costs nothing in the - * background or when the feature is off. All listeners are removed on detach / - * {@link #dispose}, so it does not leak across shell rebuilds. + *

The {@code ambient} mode (dim, mouse-transparent, drawn behind every + * screen) is no longer reachable: the wallet dropped the animated background + * setting it existed for. The flag is kept because unpicking it means editing + * the drawing code the Live page depends on, for no user-visible gain. */ public final class LiveBlocksView extends Region { private static final double TILE_W = 104; // full-mode block card (px) @@ -76,7 +75,7 @@ public void handle(long now) { sceneProperty().addListener((o, oldScene, newScene) -> onSceneChanged(newScene)); } - /** External gate: the ambient toggle, or the Live page being on screen. */ + /** External gate: whether the Live page is on screen. */ public void setActive(boolean on) { if (on == active) { return; diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LivePrefs.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LivePrefs.java deleted file mode 100644 index 87ea5dc..0000000 --- a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/live/LivePrefs.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.bloxbean.cardano.yano.wallet.ui.live; - -import java.util.prefs.Preferences; - -/** - * Persisted toggle for the opt-in animated "live chain" ambient background. - * Off by default — the animation costs frames, so a user opts in. Stored per-user - * (like the theme), independent of the wallet data directory. - */ -public final class LivePrefs { - private LivePrefs() { - } - - private static final Preferences PREFS = - Preferences.userRoot().node("com/bloxbean/cardano/yano/wallet/ui"); - private static final String KEY = "liveBackground"; - - private static volatile boolean ambientEnabled = PREFS.getBoolean(KEY, false); - // A single listener (the live shell) so a Settings toggle updates the ambient - // layer immediately. The shell registers on show and clears it on dispose. - private static volatile Runnable onChange; - - public static boolean ambientEnabled() { - return ambientEnabled; - } - - public static void setAmbientEnabled(boolean enabled) { - ambientEnabled = enabled; - PREFS.putBoolean(KEY, enabled); - Runnable listener = onChange; - if (listener != null) { - listener.run(); - } - } - - /** Register (or clear, with {@code null}) the change listener; last one wins. */ - public static void setOnChange(Runnable listener) { - onChange = listener; - } -} diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/AboutScreen.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/AboutScreen.java new file mode 100644 index 0000000..7464c8f --- /dev/null +++ b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/AboutScreen.java @@ -0,0 +1,123 @@ +package com.bloxbean.cardano.yano.wallet.ui.screens; + +import com.bloxbean.cardano.yano.wallet.ui.BuildInfo; +import com.bloxbean.cardano.yano.wallet.ui.Shell; +import com.bloxbean.cardano.yano.wallet.ui.util.Icons; +import com.bloxbean.cardano.yano.wallet.ui.util.Ui; +import javafx.geometry.Insets; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; + +/** + * Which build this is. + * + *

A top-level screen rather than a card inside Settings: the first question + * on any bug report is "which version?", and someone answering it should not + * have to know that versions live under Settings. + * + *

Every value comes from {@link BuildInfo}, generated from gradle.properties + * at build time, so this cannot drift from the release it shipped in. + */ +public class AboutScreen implements Shell.Screen { + private static final String REPO = "https://github.com/bloxbean/yano-wallet"; + + private final StackPane overlay; + private final ScrollPane root; + + public AboutScreen(StackPane overlay) { + this.overlay = overlay; + this.root = build(); + } + + private ScrollPane build() { + Label title = new Label("About"); + title.getStyleClass().add("screen-title"); + + VBox versionCard = Ui.card("Version", + mono("Yano Wallet " + BuildInfo.WALLET_VERSION), + mono("Managed node: Yano " + BuildInfo.NODE_VERSION), + mono("Runtime: " + runtimeDescription()), + mono("Platform: " + platformDescription()), + Ui.muted("Include these details in a bug report — they identify the exact " + + "build, which nothing else in the app can tell you."), + copyButton()); + + Hyperlink repo = new Hyperlink(REPO); + repo.setOnAction(e -> { + Ui.copyToClipboard(REPO); + Ui.toast(overlay, "Link copied", false); + }); + + VBox projectCard = Ui.card("Project", + Ui.muted("A full-node Cardano wallet: it runs its own Yano node, so balances " + + "and history come from a chain you validated yourself."), + repo, + Ui.muted("MIT licensed. Under active development and not audited — use test " + + "networks, and never a recovery phrase holding real funds.")); + + VBox column = new VBox(16, title, versionCard, projectCard); + column.setPadding(new Insets(24)); + column.setMaxWidth(860); + + ScrollPane scroll = new ScrollPane(column); + scroll.setFitToWidth(true); + scroll.getStyleClass().add("screen-scroll"); + return scroll; + } + + private Button copyButton() { + Button copy = new Button("Copy version details", Icons.icon(Icons.COPY, 14, "nav-icon")); + copy.getStyleClass().add("primary-button"); + copy.setOnAction(e -> { + Ui.copyToClipboard(report()); + Ui.toast(overlay, "Version details copied", false); + }); + return copy; + } + + private static Label mono(String text) { + Label label = new Label(text); + label.getStyleClass().add("mono"); + label.setWrapText(true); + return label; + } + + /** + * A native image has no JVM to report, and printing a Java version there + * would send a bug report down the wrong path — several native-image + * failures reproduce only in that build. + */ + private static String runtimeDescription() { + if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { + return "native image (no JVM)"; + } + return "Java " + Runtime.version().feature() + " (" + System.getProperty("java.vendor") + ")"; + } + + private static String platformDescription() { + return System.getProperty("os.name") + " " + System.getProperty("os.version") + + " (" + System.getProperty("os.arch") + ")"; + } + + private static String report() { + return "Yano Wallet " + BuildInfo.WALLET_VERSION + + "\nManaged node: Yano " + BuildInfo.NODE_VERSION + + "\nRuntime: " + runtimeDescription() + + "\nPlatform: " + platformDescription(); + } + + @Override + public Node root() { + return root; + } + + @Override + public void refresh() { + // Build facts are fixed for the life of the process. + } +} diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java index 0b7939c..85ec821 100644 --- a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java +++ b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/screens/SettingsScreen.java @@ -1,12 +1,9 @@ package com.bloxbean.cardano.yano.wallet.ui.screens; -import com.bloxbean.cardano.yano.wallet.ui.BuildInfo; import com.bloxbean.cardano.yano.wallet.ui.Shell; import com.bloxbean.cardano.yano.wallet.ui.contract.WalletUiController; -import com.bloxbean.cardano.yano.wallet.ui.live.LivePrefs; import com.bloxbean.cardano.yano.wallet.ui.util.ThemeManager; import com.bloxbean.cardano.yano.wallet.ui.util.Ui; -import javafx.animation.PauseTransition; import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -24,10 +21,7 @@ import javafx.scene.layout.HBox; import javafx.scene.control.TextField; import javafx.scene.layout.StackPane; -import javafx.scene.input.Clipboard; -import javafx.scene.input.ClipboardContent; import javafx.scene.layout.VBox; -import javafx.util.Duration; import java.util.Arrays; import java.util.List; @@ -144,7 +138,7 @@ private ScrollPane build() { VBox advancedCard = Ui.card("Managed node", relaysPane, filesPane); VBox column = new VBox(16, title, appearanceCard(), nodeCard, walletCard, securityCard, - dappsCard, connectorCard, advancedCard, aboutCard()); + dappsCard, connectorCard, advancedCard); column.setPadding(new Insets(24)); column.setMaxWidth(860); ScrollPane scroll = new ScrollPane(column); @@ -283,59 +277,6 @@ public void refresh() { loadSecurityKey(); } - /** - * Versions, and a one-click copy of them. The first question on any bug - * report is "which build?", and a user cannot answer it from a window title - * or a binary that reports nothing. BuildInfo is generated from - * gradle.properties at build time, so this cannot drift from the release. - */ - private VBox aboutCard() { - Label version = new Label("Yano Wallet " + BuildInfo.WALLET_VERSION); - version.getStyleClass().add("mono"); - - Label node = new Label("Managed node: Yano " + BuildInfo.NODE_VERSION); - node.getStyleClass().add("mono"); - - Label runtime = new Label("Runtime: " + runtimeDescription()); - runtime.getStyleClass().add("mono"); - - Button copy = new Button("Copy version details"); - copy.getStyleClass().add("ghost-button"); - copy.setOnAction(e -> { - ClipboardContent content = new ClipboardContent(); - content.putString(versionReport()); - Clipboard.getSystemClipboard().setContent(content); - copy.setText("Copied"); - PauseTransition reset = new PauseTransition(Duration.seconds(1.5)); - reset.setOnFinished(done -> copy.setText("Copy version details")); - reset.play(); - }); - - return Ui.card("About", version, node, runtime, - Ui.muted("Paste these details into a bug report — they identify the exact " - + "build, which the wallet cannot infer from anything else."), - copy); - } - - /** - * Native images have no JVM to report, and saying "Java 25" there would be a - * lie that sends a bug report down the wrong path. - */ - private static String runtimeDescription() { - if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { - return "native image (no JVM)"; - } - return "Java " + Runtime.version().feature() + " (" + System.getProperty("java.vendor") + ")"; - } - - private static String versionReport() { - return "Yano Wallet " + BuildInfo.WALLET_VERSION - + "\nManaged node: Yano " + BuildInfo.NODE_VERSION - + "\nRuntime: " + runtimeDescription() - + "\nOS: " + System.getProperty("os.name") + " " + System.getProperty("os.version") - + " (" + System.getProperty("os.arch") + ")"; - } - private VBox appearanceCard() { ComboBox themePicker = new ComboBox<>(); ThemeManager.themes().forEach(theme -> themePicker.getItems().add(theme.label())); @@ -352,15 +293,9 @@ private VBox appearanceCard() { } }); }); - CheckBox liveBackground = new CheckBox("Animated live-chain background"); - liveBackground.setSelected(LivePrefs.ambientEnabled()); - liveBackground.setOnAction(e -> LivePrefs.setAmbientEnabled(liveBackground.isSelected())); return Ui.card("Appearance", Ui.muted("Color theme — applies instantly and is remembered."), - themePicker, - liveBackground, - Ui.muted("A subtle animation of live blocks behind the app. Opt-in; it pauses when the " - + "window isn't focused. Open the Live page for the full view.")); + themePicker); } private void loadNodeLog() { diff --git a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/util/Icons.java b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/util/Icons.java index f766b91..f4bca4f 100644 --- a/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/util/Icons.java +++ b/wallet-ui/src/main/java/com/bloxbean/cardano/yano/wallet/ui/util/Icons.java @@ -27,6 +27,9 @@ private Icons() { + " 2-2h12M16 13h3"; public static final String LOCK = "M7 11V7a5 5 0 0 1 10 0v4M5 11h14v10H5V11z"; // Filled equalizer bars — reads as live activity/stats (must be solid, not stroked). + /** "i" in a circle. */ + public static final String ABOUT = "M12 3a9 9 0 1 0 9 9 9 9 0 0 0-9-9zm0 4h.01M11 11h1v6h1"; + public static final String LIVE = "M4 13h3v7H4v-7z M10 8h3v12h-3V8z M16 3h3v17h-3V3z"; public static Region icon(String svgPath, double size, String styleClass) {