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)}`);