From 08dff3e60dd93d697f3a4fa92f95a3746c086252 Mon Sep 17 00:00:00 2001 From: Marc Froehlich Date: Mon, 20 Jul 2026 23:01:18 +0200 Subject: [PATCH] manual refactoring + versioninfo xml refactoring --- .../kst4contest/ApplicationConstants.java | 9 ++- .../controller/ChatController.java | 2 +- .../MessageBusManagementThread.java | 2 +- .../kst4contest/controller/UpdateChecker.java | 10 +++ .../kst4contest/model/ChatPreferences.java | 4 +- .../kst4contest/model/UpdateInformation.java | 26 ++++++- .../java/kst4contest/utils/VersionUtils.java | 68 +++++++++++++++++++ .../view/Kst4ContestApplication.java | 38 ++++++++--- website/src/_data/versionInfo.js | 13 +++- 9 files changed, 154 insertions(+), 18 deletions(-) create mode 100644 src/main/java/kst4contest/utils/VersionUtils.java diff --git a/src/main/java/kst4contest/ApplicationConstants.java b/src/main/java/kst4contest/ApplicationConstants.java index b595494..d0f80b1 100644 --- a/src/main/java/kst4contest/ApplicationConstants.java +++ b/src/main/java/kst4contest/ApplicationConstants.java @@ -18,8 +18,15 @@ public class ApplicationConstants { public static final String APPLICATION_NAME = "praktiKST"; /** - * Name of file to store preferences in. + * Version shown to the user and used for semantic version comparison. */ + public static final String APPLICATION_CURRENT_VERSION = "1.42"; + + /** + * Legacy numeric representation used only while older update feeds and + * application versions still exist. + */ + @Deprecated public static final double APPLICATION_CURRENTVERSIONNUMBER = 1.42; public static final String VERSIONINFOURLFORUPDATES_KST4CONTEST = "https://kst4contest.hamradioonline.de/kst4ContestVersionInfo.xml"; diff --git a/src/main/java/kst4contest/controller/ChatController.java b/src/main/java/kst4contest/controller/ChatController.java index 603d2c1..a3bb601 100644 --- a/src/main/java/kst4contest/controller/ChatController.java +++ b/src/main/java/kst4contest/controller/ChatController.java @@ -2533,7 +2533,7 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList String loginString = ""; loginString = "LOGINC|" + chatPreferences.getStn_loginCallSign() + "|" + chatPreferences.getStn_loginPassword() - + "|" + chatPreferences.getLoginChatCategoryMain().getCategoryNumber() + "|praktiKST v" + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER + + "|" + chatPreferences.getLoginChatCategoryMain().getCategoryNumber() + "|praktiKST v" + ApplicationConstants.APPLICATION_CURRENT_VERSION + "|25|0|1|" + "0" + "|0|"; // System.out.println(loginString); diff --git a/src/main/java/kst4contest/controller/MessageBusManagementThread.java b/src/main/java/kst4contest/controller/MessageBusManagementThread.java index 13bcf36..93bdfb8 100644 --- a/src/main/java/kst4contest/controller/MessageBusManagementThread.java +++ b/src/main/java/kst4contest/controller/MessageBusManagementThread.java @@ -829,7 +829,7 @@ public class MessageBusManagementThread extends Thread { versionInfo.setSender(itsMe); versionInfo.setReceiver(newMessageArrived.getSender()); - versionInfo.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign() + " " + ApplicationConstants.AUTOANSWER_PREFIX + " " + "KST4Contest " + " v" + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER + " by DO5AMF"); + versionInfo.setMessageText("/CQ " + newMessageArrived.getSender().getCallSign() + " " + ApplicationConstants.AUTOANSWER_PREFIX + " " + "KST4Contest " + " v" + ApplicationConstants.APPLICATION_CURRENT_VERSION + " by DO5AMF"); this.client.getMessageTXBus().add(versionInfo); } diff --git a/src/main/java/kst4contest/controller/UpdateChecker.java b/src/main/java/kst4contest/controller/UpdateChecker.java index 97ad925..0ebc38d 100644 --- a/src/main/java/kst4contest/controller/UpdateChecker.java +++ b/src/main/java/kst4contest/controller/UpdateChecker.java @@ -108,6 +108,16 @@ public class UpdateChecker { Element element = (Element) node; updateInfos.setLatestVersionNumberOnServer(Double.parseDouble(element.getElementsByTagName("versionNumber").item(0).getTextContent())); + + NodeList semanticVersionNodes = + element.getElementsByTagName("semanticVersion"); + + if (semanticVersionNodes.getLength() > 0) { + updateInfos.setLatestSemanticVersionOnServer( + semanticVersionNodes.item(0).getTextContent() + ); + } + updateInfos.setAdminMessage(element.getElementsByTagName("adminMessage").item(0).getTextContent()); updateInfos.setMajorChanges(element.getElementsByTagName("majorChanges").item(0) .getTextContent()); diff --git a/src/main/java/kst4contest/model/ChatPreferences.java b/src/main/java/kst4contest/model/ChatPreferences.java index ac598ae..ad78eb8 100644 --- a/src/main/java/kst4contest/model/ChatPreferences.java +++ b/src/main/java/kst4contest/model/ChatPreferences.java @@ -307,8 +307,8 @@ public class ChatPreferences { String messageHandling_unworkedStnRequesterBeaconsText; String messageHandling_beaconUnworkedstationsPrefix; - String messageHandling_autoAnswerTextMainCat = "Hi, sry I am not qrv, just testing new features of KST4Contest " + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER; - String messageHandling_autoAnswerTextSecondCat = "Hi, sry I am not qrv, just testing new features of KST4Contest " + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER; + String messageHandling_autoAnswerTextMainCat = "Hi, sry I am not qrv, just testing new features of KST4Contest " + ApplicationConstants.APPLICATION_CURRENT_VERSION; + String messageHandling_autoAnswerTextSecondCat = "Hi, sry I am not qrv, just testing new features of KST4Contest " + ApplicationConstants.APPLICATION_CURRENT_VERSION; boolean messageHandling_autoAnswerEnabled = false; boolean messageHandling_autoAnswerEnabledSecondCat = false; diff --git a/src/main/java/kst4contest/model/UpdateInformation.java b/src/main/java/kst4contest/model/UpdateInformation.java index a4dcb32..3b2c0d9 100644 --- a/src/main/java/kst4contest/model/UpdateInformation.java +++ b/src/main/java/kst4contest/model/UpdateInformation.java @@ -3,7 +3,10 @@ package kst4contest.model; import java.util.ArrayList; public class UpdateInformation { - double latestVersionNumberOnServer = 1.26; //dummy value to prevent nullpointerexc +// double latestVersionNumberOnServer = 1.26; //dummy value to prevent nullpointerexc + double latestVersionNumberOnServer = 0.0; + String latestSemanticVersionOnServer = ""; + String adminMessage =""; String majorChanges =""; String latestVersionPathOnWebserver=""; @@ -36,6 +39,27 @@ public class UpdateInformation { public void setLatestVersionNumberOnServer(double latestVersionNumberOnServer) { this.latestVersionNumberOnServer = latestVersionNumberOnServer; } + public String getLatestSemanticVersionOnServer() { + return latestSemanticVersionOnServer; + } + + public void setLatestSemanticVersionOnServer(String latestSemanticVersionOnServer) { + this.latestSemanticVersionOnServer = + latestSemanticVersionOnServer == null ? "" : latestSemanticVersionOnServer.trim(); + } + + public boolean hasSemanticVersion() { + return !latestSemanticVersionOnServer.isBlank(); + } + + public String getLatestVersionForDisplay() { + if (hasSemanticVersion()) { + return latestSemanticVersionOnServer; + } + + return Double.toString(latestVersionNumberOnServer); + } + public String getAdminMessage() { return adminMessage; diff --git a/src/main/java/kst4contest/utils/VersionUtils.java b/src/main/java/kst4contest/utils/VersionUtils.java new file mode 100644 index 0000000..f07130f --- /dev/null +++ b/src/main/java/kst4contest/utils/VersionUtils.java @@ -0,0 +1,68 @@ +package kst4contest.utils; + +public final class VersionUtils { + + private VersionUtils() { + } + + /** + * Compares numeric release versions such as 1.41, 1.41.1 and 1.41.10. + * + * Pre-release and build suffixes are ignored because the update feed + * currently publishes stable releases only. + */ + public static int compareStableVersions(String left, String right) { + int[] leftParts = parseVersion(left); + int[] rightParts = parseVersion(right); + int partCount = Math.max(leftParts.length, rightParts.length); + + for (int index = 0; index < partCount; index++) { + int leftPart = index < leftParts.length ? leftParts[index] : 0; + int rightPart = index < rightParts.length ? rightParts[index] : 0; + + int comparison = Integer.compare(leftPart, rightPart); + if (comparison != 0) { + return comparison; + } + } + + return 0; + } + + private static int[] parseVersion(String version) { + if (version == null || version.isBlank()) { + throw new IllegalArgumentException("Version must not be empty"); + } + + String normalized = version.trim(); + + if (normalized.startsWith("v") || normalized.startsWith("V")) { + normalized = normalized.substring(1); + } + + int hyphenIndex = normalized.indexOf('-'); + int plusIndex = normalized.indexOf('+'); + int suffixIndex; + + if (hyphenIndex < 0) { + suffixIndex = plusIndex; + } else if (plusIndex < 0) { + suffixIndex = hyphenIndex; + } else { + suffixIndex = Math.min(hyphenIndex, plusIndex); + } + + if (suffixIndex >= 0) { + normalized = normalized.substring(0, suffixIndex); + } + + String[] textParts = normalized.split("\\."); + int[] numericParts = new int[textParts.length]; + + for (int index = 0; index < textParts.length; index++) { + numericParts[index] = Integer.parseInt(textParts[index]); + } + + return numericParts; + } +} \ No newline at end of file diff --git a/src/main/java/kst4contest/view/Kst4ContestApplication.java b/src/main/java/kst4contest/view/Kst4ContestApplication.java index 0f0ba6a..059dd35 100644 --- a/src/main/java/kst4contest/view/Kst4ContestApplication.java +++ b/src/main/java/kst4contest/view/Kst4ContestApplication.java @@ -1,4 +1,5 @@ package kst4contest.view; +import kst4contest.utils.VersionUtils; import java.io.File; import java.io.IOException; @@ -5079,7 +5080,7 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL Alert a = new Alert(AlertType.INFORMATION); a.setTitle("About kst4contest"); - a.setHeaderText("kst4Contest " + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER + ": ON4KST Chatclient by DO5AMF"); + a.setHeaderText("kst4Contest " + ApplicationConstants.APPLICATION_CURRENT_VERSION + ": ON4KST Chatclient by DO5AMF"); a.setContentText(chatcontroller.getChatPreferences().getProgramVersion()); a.show(); } @@ -8070,12 +8071,12 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL stage_updateStage.setAlwaysOnTop(true); - Label lblUpdateInfo = new Label("Update aviable!"); - Label lblUpdateInfo2 = new Label("Your Software version: "); - Label lblUpdateInfo3 = new Label("Newest Software version: "); - Label lblUpdateInfoChanges = new Label("Major Changes: "); - Label lblUpdateInfoAdminMessage = new Label("Admin Message: "); - Label lblUpdateInfoDownload = new Label("Downloadable here: " ); + Label lblUpdateInfo = new Label("Update available!"); + Label lblUpdateInfo2 = new Label("Installed version:"); + Label lblUpdateInfo3 = new Label("Latest stable version:"); + Label lblUpdateInfoChanges = new Label("Main changes:"); + Label lblUpdateInfoAdminMessage = new Label("Additional information:"); + Label lblUpdateInfoDownload = new Label("Download:"); TreeView treeView = new TreeView(); @@ -8094,16 +8095,16 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL vbxUpdateWindow.getChildren().add(upd_gridPaneUpd); upd_gridPaneUpd.add(lblUpdateInfo, 0,0,1,1); upd_gridPaneUpd.add(lblUpdateInfo2, 0,1,1,1); - upd_gridPaneUpd.add(new Label("kst4Contest " + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER+""), 1,1,1,1); + upd_gridPaneUpd.add(new Label("kst4Contest " + ApplicationConstants.APPLICATION_CURRENT_VERSION), 1,1,1,1); upd_gridPaneUpd.add(lblUpdateInfo3, 0,2,1,1); - upd_gridPaneUpd.add(new Label("kst4Contest " + chatcontroller.getUpdateInformation().getLatestVersionNumberOnServer()+""), 1,2,1,1); + upd_gridPaneUpd.add(new Label("KST4Contest " + chatcontroller.getUpdateInformation().getLatestVersionForDisplay()), 1,2,1,1); upd_gridPaneUpd.add(lblUpdateInfoChanges, 0,3,1,1); upd_gridPaneUpd.add(new Label(chatcontroller.getUpdateInformation().getMajorChanges()), 1,3,1,1); upd_gridPaneUpd.add(lblUpdateInfoAdminMessage, 0,4,1,1); upd_gridPaneUpd.add(new Label(chatcontroller.getUpdateInformation().getAdminMessage()), 1,4,1,1); upd_gridPaneUpd.add(lblUpdateInfoDownload, 0,5,1,1); - Hyperlink link = new Hyperlink("Download here"); + Hyperlink link = new Hyperlink("Open release page"); link.setOnAction(e -> { getHostServices().showDocument(chatcontroller.getUpdateInformation().getLatestVersionPathOnWebserver()); // System.out.println("The Hyperlink was clicked!"); @@ -8162,7 +8163,22 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL stage_updateStage.setScene(new Scene(vbxUpdateWindow, chatcontroller.getChatPreferences().getGUIstage_updateStage_SceneSizeHW()[0], chatcontroller.getChatPreferences().getGUIstage_updateStage_SceneSizeHW()[1])); - if (chatcontroller.getUpdateInformation().getLatestVersionNumberOnServer() > ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER) { +// if (chatcontroller.getUpdateInformation().getLatestVersionNumberOnServer() > ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER) { + + boolean updateAvailable; + + if (chatcontroller.getUpdateInformation().hasSemanticVersion()) { + updateAvailable = VersionUtils.compareStableVersions( + chatcontroller.getUpdateInformation().getLatestSemanticVersionOnServer(), + ApplicationConstants.APPLICATION_CURRENT_VERSION + ) > 0; + } else { + updateAvailable = + chatcontroller.getUpdateInformation().getLatestVersionNumberOnServer() + > ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER; + } + + if (updateAvailable) { stage_updateStage.show(); } else { diff --git a/website/src/_data/versionInfo.js b/website/src/_data/versionInfo.js index 77413ba..b123900 100644 --- a/website/src/_data/versionInfo.js +++ b/website/src/_data/versionInfo.js @@ -30,6 +30,13 @@ function toAppVersionNumber(tag) { return /^0*$/.test(patch) ? `${major}.${minor}` : `${major}.${minor}${patch}`; } +function toSemanticVersion(tag) { + return tag + .replace(/^v/, "") + .split("-")[0] + .split("+")[0]; +} + function escapeXml(value) { return String(value ?? "") .replace(/&/g, "&") @@ -132,6 +139,9 @@ module.exports = async function () { if (stable) { const latestIssues = await getIssuesForRelease("1970-01-01T00:00:00Z", stable.publishedAt); parts.push(` ${escapeXml(toAppVersionNumber(latestTag))}`); + parts.push( + ` https://github.com/${REPO}/releases/tag/${latestTag}` + ); parts.push(" "); parts.push(` ${escapeXml(latestIssues.added.slice(0, 300))}`); parts.push( @@ -158,7 +168,8 @@ module.exports = async function () { const issues = await getIssuesForRelease(since, until); parts.push(" "); - parts.push(` ${escapeXml(toAppVersionNumber(rel.tagName))}`); + + parts.push(` ${escapeXml(toSemanticVersion(rel.tagName))}`); parts.push(` ${escapeXml(until.slice(0, 10))}`); parts.push(` ${escapeXml(rel.name)}`); parts.push(` ${escapeXml(issues.added)}`);