From 7611d56fd665ced328d1693a5aad89826b011975 Mon Sep 17 00:00:00 2001
From: Martin Straka <martin.straka@nic.cz>
Date: Thu, 16 Jan 2025 10:49:11 +0100
Subject: [PATCH 1/9] Show change log dialog after update on new version.

---
 CMakeLists.txt                  |  1 +
 qml/components/ChangeLogBox.qml | 98 +++++++++++++++++++++++++++++++++
 qml/main.qml                    |  8 +++
 qml/pages/PageAboutApp.qml      |  6 ++
 res/qml.qrc                     |  1 +
 src/main.cpp                    |  1 +
 src/setwrapper.cpp              | 69 +++++++++++++++++++++++
 src/setwrapper.h                |  8 +++
 8 files changed, 192 insertions(+)
 create mode 100644 qml/components/ChangeLogBox.qml

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 608346e75..c78116890 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -238,6 +238,7 @@ qt_add_qml_module(mobile-datovka
         res/../qml/components/FilterBar.qml
         res/../qml/components/GovFormList.qml
         res/../qml/components/GovServiceList.qml
+        res/../qml/components/ChangeLogBox.qml
         res/../qml/components/MessageBox.qml
         res/../qml/components/MessageList.qml
         res/../qml/components/PageHeader.qml
diff --git a/qml/components/ChangeLogBox.qml b/qml/components/ChangeLogBox.qml
new file mode 100644
index 000000000..dc8dd84b2
--- /dev/null
+++ b/qml/components/ChangeLogBox.qml
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014-2025 CZ.NIC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations including
+ * the two.
+ */
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.2
+
+/*
+ * Provides a simple change log dialog.
+ */
+Popup {
+    id: root
+    anchors.centerIn: parent
+    modal: true
+
+    property int preferredMinWidth: 280
+    property string logContent: qsTr("
+    Added a preferences editor.
+
+    Using dedicated redirection URL to access donation page.
+
+    Custom images can be assigned to individual data boxes as logos in the data-box list.
+
+    Fixed white border around launcher icon in iOS.
+
+    On application start-up when INI configuration is missing the application searches for a copy before creating a blank INI file.
+    ")
+
+    /* Public interface. */
+    function showChangeLog() {
+        changeLogText.text = logContent
+        root.open()
+    }
+
+    background: Rectangle {
+        color: datovkaPalette.base
+        border.color: datovkaPalette.text
+        radius: defaultMargin
+    }
+
+    ColumnLayout {
+        spacing: defaultMargin * 2
+        AccessibleText {
+            font.bold: true
+            Layout.alignment: Qt.AlignCenter
+            color: datovkaPalette.highlightedText
+            text: qsTr("Version") + ": " + Qt.application.version
+        }
+        AccessibleText {
+            Layout.preferredWidth: root.preferredMinWidth
+            horizontalAlignment : Text.Center
+            wrapMode: Text.Wrap
+            font.bold: true
+            text: qsTr("What is news?")
+        }
+        Flickable {
+            clip: true
+            Layout.preferredWidth: root.preferredMinWidth
+            implicitHeight: preferredMinWidth
+            contentHeight: flickContent.implicitHeight
+            Pane {
+                id: flickContent
+                anchors.fill: parent
+                AccessibleText {
+                    id: changeLogText
+                    width: parent.width
+                    wrapMode: Text.WordWrap
+                }
+            }
+            ScrollIndicator.vertical: ScrollIndicator {}
+        }
+        AccessibleButton {
+            Layout.alignment: Qt.AlignCenter
+            text: "OK"
+            onClicked: root.close()
+        }
+    }
+}
diff --git a/qml/main.qml b/qml/main.qml
index 7a3c4b7f9..3abb7b1ec 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -262,6 +262,10 @@ ApplicationWindow {
         id: okMsgBox
     }
 
+    ChangeLogBox {
+        id: changeLogBox
+    }
+
     DrawerMenuDatovka {
         id: drawerMenuDatovka
     }
@@ -480,6 +484,10 @@ ApplicationWindow {
             target: settings
             function onRunOnAppStartUpSig() {
                 console.log("Running actions after application start-up.")
+                var isNewVersion = settings.isNewVersion()
+                if (isNewVersion) {
+                    changeLogBox.showChangeLog()
+                }
                 var areNews = messages.checkNewDatabasesFormat()
                 if (!areNews) {
                     pageView.push(pageConvertDatabase, {
diff --git a/qml/pages/PageAboutApp.qml b/qml/pages/PageAboutApp.qml
index 7d661a8c9..bc0709a58 100644
--- a/qml/pages/PageAboutApp.qml
+++ b/qml/pages/PageAboutApp.qml
@@ -88,6 +88,12 @@ Page {
                             + "<br/>"
                             + "<a href=\"%1\">%2</a>".arg("https://datovka.nic.cz/redirect/donation-mobile.html").arg(qsTr("Make a donation."))
                     }
+                    AccessibleButton {
+                        anchors.horizontalCenter: parent.horizontalCenter
+                        text: qsTr("Show ChangeLog")
+                        accessibleName: qsTr("What is news?")
+                        onClicked: changeLogBox.showChangeLog()
+                    }
                     AccessibleTextInfo {
                         horizontalAlignment: Text.AlignHCenter
                         textFormat: TextEdit.RichText
diff --git a/res/qml.qrc b/res/qml.qrc
index c44523fa6..cae41eb70 100644
--- a/res/qml.qrc
+++ b/res/qml.qrc
@@ -24,6 +24,7 @@
         <file>../qml/components/FilterBar.qml</file>
         <file>../qml/components/GovFormList.qml</file>
         <file>../qml/components/GovServiceList.qml</file>
+        <file>../qml/components/ChangeLogBox.qml</file>
         <file>../qml/components/MessageBox.qml</file>
         <file>../qml/components/MessageList.qml</file>
         <file>../qml/components/PageHeader.qml</file>
diff --git a/src/main.cpp b/src/main.cpp
index 44d9d51a5..a4dbab879 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -194,6 +194,7 @@ const struct QmlTypeEntry qmlComponents[] = {
 	{ "FilterBar", 1, 0 },
 	{ "GovFormList", 1, 0 },
 	{ "GovServiceList", 1, 0 },
+	{ "ChangeLogBox", 1, 0 },
 	{ "MessageBox", 1, 0 },
 	{ "MessageList", 1, 0 },
 	{ "PageHeader", 1, 0 },
diff --git a/src/setwrapper.cpp b/src/setwrapper.cpp
index 3759a6803..2f54d5ec5 100644
--- a/src/setwrapper.cpp
+++ b/src/setwrapper.cpp
@@ -22,6 +22,7 @@
  */
 
 #include <QtGlobal> /* QT_VERSION, qVersion() */
+#include <QVersionNumber>
 
 #if defined (Q_OS_ANDROID)
 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
@@ -782,3 +783,71 @@ bool GlobalSettingsQmlWrapper::useIosDocumentPicker(void)
 		return false;
 	}
 }
+
+/*!
+ * @brief Compare current app version and pref db version.
+ *
+ * @param[in] cVersion App current version string.
+ * @param[in] dbVersion Pref database version string.
+ * @return True if current app version is higher.
+ */
+static
+bool compareVersionStrings(const QString &cVersion, const QString &dbVersion)
+{
+	QVersionNumber v1 = QVersionNumber::fromString(cVersion);
+	if (v1.isNull()) {
+		logErrorNL(
+		    "Version string '%s' does not match required format.",
+		    cVersion.toUtf8().constData());
+		return false;
+	}
+	QVersionNumber v2 = QVersionNumber::fromString(dbVersion);
+	if (v2.isNull()) {
+		logErrorNL(
+		    "Version string '%s' does not match required format.",
+		    dbVersion.toUtf8().constData());
+		return false;
+	}
+
+	int cmp = QVersionNumber::compare(v1, v2);
+	if (cmp < 0) {
+		return false;
+	} else if (cmp == 0) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+bool GlobalSettingsQmlWrapper::isNewVersion(void)
+{
+	bool isNew = true;
+	QString dbVersion;
+
+	if (GlobInstcs::prefsPtr != Q_NULLPTR) {
+		GlobInstcs::prefsPtr->strVal("app.version", dbVersion);
+	} else {
+		Q_ASSERT(0);
+	}
+	if (Q_UNLIKELY(dbVersion.isEmpty())) {
+		if (GlobInstcs::prefsPtr != Q_NULLPTR) {
+			GlobInstcs::prefsPtr->setStrVal("app.version", VERSION);
+			return isNew;
+		} else {
+			Q_ASSERT(0);
+		}
+	}
+
+	isNew = compareVersionStrings(VERSION, dbVersion);
+
+	if (isNew) {
+		if (GlobInstcs::prefsPtr != Q_NULLPTR) {
+			GlobInstcs::prefsPtr->setStrVal("app.version", VERSION);
+			return isNew;
+		} else {
+			Q_ASSERT(0);
+		}
+	}
+
+	return isNew;
+}
diff --git a/src/setwrapper.h b/src/setwrapper.h
index 718863aa0..8d3adf1e7 100644
--- a/src/setwrapper.h
+++ b/src/setwrapper.h
@@ -491,6 +491,14 @@ public:
 	Q_INVOKABLE static
 	bool useIosDocumentPicker(void);
 
+	/*!
+	 * @brief Check if new version after first startup.
+	 *
+	 * @return True if it is new version after first startup.
+	*/
+	Q_INVOKABLE static
+	bool isNewVersion(void);
+
 signals:
 	/*!
 	 * @brief Send PIN verification result to QML.
-- 
GitLab


From e3031004c58795a394076968abbce98d4cd901a2 Mon Sep 17 00:00:00 2001
From: Martin Straka <martin.straka@nic.cz>
Date: Thu, 16 Jan 2025 14:14:55 +0100
Subject: [PATCH 2/9] Added textarea border.

---
 qml/components/ChangeLogBox.qml | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/qml/components/ChangeLogBox.qml b/qml/components/ChangeLogBox.qml
index dc8dd84b2..a3dca80ea 100644
--- a/qml/components/ChangeLogBox.qml
+++ b/qml/components/ChangeLogBox.qml
@@ -34,8 +34,7 @@ Popup {
     modal: true
 
     property int preferredMinWidth: 280
-    property string logContent: qsTr("
-    Added a preferences editor.
+    property string logContent: qsTr("Added a preferences editor.
 
     Using dedicated redirection URL to access donation page.
 
@@ -43,8 +42,7 @@ Popup {
 
     Fixed white border around launcher icon in iOS.
 
-    On application start-up when INI configuration is missing the application searches for a copy before creating a blank INI file.
-    ")
+    On application start-up when INI configuration is missing the application searches for a copy before creating a blank INI file.")
 
     /* Public interface. */
     function showChangeLog() {
@@ -73,21 +71,28 @@ Popup {
             font.bold: true
             text: qsTr("What is news?")
         }
-        Flickable {
-            clip: true
+        Rectangle {
             Layout.preferredWidth: root.preferredMinWidth
             implicitHeight: preferredMinWidth
-            contentHeight: flickContent.implicitHeight
-            Pane {
-                id: flickContent
+            color: "transparent"
+            border.color: datovkaPalette.line
+            border.width: 1
+            Flickable {
                 anchors.fill: parent
-                AccessibleText {
-                    id: changeLogText
-                    width: parent.width
-                    wrapMode: Text.WordWrap
+                anchors.margins: 1
+                contentHeight: flickContent.implicitHeight
+                clip: true
+                Pane {
+                    id: flickContent
+                    anchors.fill: parent
+                    AccessibleText {
+                        id: changeLogText
+                        width: parent.width
+                        wrapMode: Text.WordWrap
+                    }
                 }
+                ScrollIndicator.vertical: ScrollIndicator {}
             }
-            ScrollIndicator.vertical: ScrollIndicator {}
         }
         AccessibleButton {
             Layout.alignment: Qt.AlignCenter
-- 
GitLab


From 536e4f26e85ce69b35dfd9da4a26bd2f0fba50fc Mon Sep 17 00:00:00 2001
From: Martin Straka <martin.straka@nic.cz>
Date: Thu, 16 Jan 2025 15:29:38 +0100
Subject: [PATCH 3/9] Moved changelog content into separate file/class.

---
 CMakeLists.txt                  |  1 +
 mobile-datovka.pro              |  2 ++
 qml/components/ChangeLogBox.qml | 12 ++--------
 src/changelog.cpp               | 42 +++++++++++++++++++++++++++++++++
 src/changelog.h                 | 40 +++++++++++++++++++++++++++++++
 src/setwrapper.cpp              |  6 +++++
 src/setwrapper.h                |  8 +++++++
 7 files changed, 101 insertions(+), 10 deletions(-)
 create mode 100644 src/changelog.cpp
 create mode 100644 src/changelog.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c78116890..8a517c523 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -109,6 +109,7 @@ qt_add_executable(mobile-datovka
     src/gov_services/models/gov_form_list_model.cpp src/gov_services/models/gov_form_list_model.h
     src/gov_services/models/gov_service_list_model.cpp src/gov_services/models/gov_service_list_model.h
     src/gov_wrapper.cpp src/gov_wrapper.h
+    src/changelog.cpp src/changelog.h
     src/initialisation.cpp src/initialisation.h
     src/io/filesystem.cpp src/io/filesystem.h
     src/isds/conversion/isds_conversion.cpp src/isds/conversion/isds_conversion.h
diff --git a/mobile-datovka.pro b/mobile-datovka.pro
index b6c4c4a72..15415d971 100644
--- a/mobile-datovka.pro
+++ b/mobile-datovka.pro
@@ -242,6 +242,7 @@ SOURCES += \
     src/gov_services/models/gov_form_list_model.cpp \
     src/gov_services/models/gov_service_list_model.cpp \
     src/gov_wrapper.cpp \
+    src/changelog.cpp \
     src/initialisation.cpp \
     src/io/filesystem.cpp \
     src/isds/conversion/isds_conversion.cpp \
@@ -426,6 +427,7 @@ HEADERS += \
     src/gov_services/models/gov_form_list_model.h \
     src/gov_services/models/gov_service_list_model.h \
     src/gov_wrapper.h \
+    src/changelog.h \
     src/initialisation.h \
     src/io/filesystem.h \
     src/isds/conversion/isds_conversion.h \
diff --git a/qml/components/ChangeLogBox.qml b/qml/components/ChangeLogBox.qml
index a3dca80ea..13b0b172b 100644
--- a/qml/components/ChangeLogBox.qml
+++ b/qml/components/ChangeLogBox.qml
@@ -34,19 +34,10 @@ Popup {
     modal: true
 
     property int preferredMinWidth: 280
-    property string logContent: qsTr("Added a preferences editor.
-
-    Using dedicated redirection URL to access donation page.
-
-    Custom images can be assigned to individual data boxes as logos in the data-box list.
-
-    Fixed white border around launcher icon in iOS.
-
-    On application start-up when INI configuration is missing the application searches for a copy before creating a blank INI file.")
 
     /* Public interface. */
     function showChangeLog() {
-        changeLogText.text = logContent
+        changeLogText.text = settings.loadChangeLogText()
         root.open()
     }
 
@@ -89,6 +80,7 @@ Popup {
                         id: changeLogText
                         width: parent.width
                         wrapMode: Text.WordWrap
+                        textFormat: TextEdit.RichText
                     }
                 }
                 ScrollIndicator.vertical: ScrollIndicator {}
diff --git a/src/changelog.cpp b/src/changelog.cpp
new file mode 100644
index 000000000..77bb70944
--- /dev/null
+++ b/src/changelog.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014-2025 CZ.NIC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations including
+ * the two.
+ */
+
+#include "src/changelog.h"
+
+#define textLineNL(text) \
+	(QLatin1String("<style>li{margin-left:-30px;}</style><ul><li>") + (text) + QLatin1String("</li></ul>"))
+
+QString ChangeLog::changeLogContent(void)
+{
+	QString content;
+
+	content.append(textLineNL(tr("Added a preferences editor.")));
+	content.append(textLineNL(tr("Custom images can be assigned to individual data boxes as logos in the data-box list.")));
+	content.append(textLineNL(tr("Using dedicated redirection URL to access donation page.")));
+	content.append(textLineNL(tr("INI configuration file is written in three stages. A copy is written then the original is removed and finally the copy replaces the original.")));
+	content.append(textLineNL(tr("On application start-up when INI configuration is missing the application searches for a copy before creating a blank INI file.")));
+	content.append(textLineNL(tr("Fixed white border around launcher icon in iOS.")));
+	content.append(textLineNL(tr("Fixed logging of debug information when building with cmake.")));
+
+	return content;
+}
diff --git a/src/changelog.h b/src/changelog.h
new file mode 100644
index 000000000..6934d3127
--- /dev/null
+++ b/src/changelog.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014-2025 CZ.NIC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations including
+ * the two.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QString>
+
+class ChangeLog : public QObject {
+    Q_OBJECT
+
+public:
+	/*!
+	 * @brief Changelog text.
+	 *
+	 * @return Changelog text.
+	 */
+	static
+	QString changeLogContent(void);
+};
diff --git a/src/setwrapper.cpp b/src/setwrapper.cpp
index 2f54d5ec5..a32978c75 100644
--- a/src/setwrapper.cpp
+++ b/src/setwrapper.cpp
@@ -45,6 +45,7 @@
 #include "src/datovka_shared/utility/date_time.h"
 #include "src/font/font.h"
 #include "src/global.h"
+#include "src/changelog.h"
 #include "src/io/filesystem.h"
 #include "src/settings/accounts.h"
 #include "src/settings/ini_preferences.h"
@@ -851,3 +852,8 @@ bool GlobalSettingsQmlWrapper::isNewVersion(void)
 
 	return isNew;
 }
+
+QString GlobalSettingsQmlWrapper::loadChangeLogText(void)
+{
+	return ChangeLog::changeLogContent();
+}
diff --git a/src/setwrapper.h b/src/setwrapper.h
index 8d3adf1e7..9ac28a408 100644
--- a/src/setwrapper.h
+++ b/src/setwrapper.h
@@ -499,6 +499,14 @@ public:
 	Q_INVOKABLE static
 	bool isNewVersion(void);
 
+	/*!
+	 * @brief Load changelog content.
+	 *
+	 * @return Changelog text.
+	*/
+	Q_INVOKABLE static
+	QString loadChangeLogText(void);
+
 signals:
 	/*!
 	 * @brief Send PIN verification result to QML.
-- 
GitLab


From cbf1cc02630868cb4b30bfaae34b2101ce225a5e Mon Sep 17 00:00:00 2001
From: Karel Slany <karel.slany@nic.cz>
Date: Tue, 18 Feb 2025 13:47:36 +0100
Subject: [PATCH 4/9] Moved code shared with the desktop application.

---
 mobile-datovka.pro                            |   5 +-
 src/{changelog.cpp => app_version_info.cpp}   |   4 +-
 src/datovka_shared/app_version_info.cpp       | 168 ++++++++++++++++++
 .../app_version_info.h}                       |  26 ++-
 src/setwrapper.cpp                            |  54 +-----
 5 files changed, 202 insertions(+), 55 deletions(-)
 rename src/{changelog.cpp => app_version_info.cpp} (95%)
 create mode 100644 src/datovka_shared/app_version_info.cpp
 rename src/{changelog.h => datovka_shared/app_version_info.h} (57%)

diff --git a/mobile-datovka.pro b/mobile-datovka.pro
index 15415d971..734d849a8 100644
--- a/mobile-datovka.pro
+++ b/mobile-datovka.pro
@@ -164,9 +164,11 @@ TRANSLATIONS_FILES += \
     res/locale/datovka_uk.qm
 
 SOURCES += \
+    src/app_version_info.cpp \
     src/auxiliaries/email_helper.cpp \
     src/auxiliaries/ios_helper.cpp \
     src/backup_zip.cpp \
+    src/datovka_shared/app_version_info.cpp \
     src/datovka_shared/compat_qt/random.cpp \
     src/datovka_shared/graphics/colour.cpp \
     src/datovka_shared/gov_services/helper.cpp \
@@ -242,7 +244,6 @@ SOURCES += \
     src/gov_services/models/gov_form_list_model.cpp \
     src/gov_services/models/gov_service_list_model.cpp \
     src/gov_wrapper.cpp \
-    src/changelog.cpp \
     src/initialisation.cpp \
     src/io/filesystem.cpp \
     src/isds/conversion/isds_conversion.cpp \
@@ -344,6 +345,7 @@ HEADERS += \
     src/auxiliaries/email_helper.h \
     src/auxiliaries/ios_helper.h \
     src/backup_zip.h \
+    src/datovka_shared/app_version_info.h \
     src/datovka_shared/compat/compiler.h \
     src/datovka_shared/compat_qt/misc.h \
     src/datovka_shared/compat_qt/random.h \
@@ -427,7 +429,6 @@ HEADERS += \
     src/gov_services/models/gov_form_list_model.h \
     src/gov_services/models/gov_service_list_model.h \
     src/gov_wrapper.h \
-    src/changelog.h \
     src/initialisation.h \
     src/io/filesystem.h \
     src/isds/conversion/isds_conversion.h \
diff --git a/src/changelog.cpp b/src/app_version_info.cpp
similarity index 95%
rename from src/changelog.cpp
rename to src/app_version_info.cpp
index 77bb70944..b51dee8e2 100644
--- a/src/changelog.cpp
+++ b/src/app_version_info.cpp
@@ -21,12 +21,12 @@
  * the two.
  */
 
-#include "src/changelog.h"
+#include "src/datovka_shared/app_version_info.h"
 
 #define textLineNL(text) \
 	(QLatin1String("<style>li{margin-left:-30px;}</style><ul><li>") + (text) + QLatin1String("</li></ul>"))
 
-QString ChangeLog::changeLogContent(void)
+QString AppVersionInfo::releaseNewsText(void)
 {
 	QString content;
 
diff --git a/src/datovka_shared/app_version_info.cpp b/src/datovka_shared/app_version_info.cpp
new file mode 100644
index 000000000..da5ad0a2c
--- /dev/null
+++ b/src/datovka_shared/app_version_info.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014-2025 CZ.NIC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations including
+ * the two.
+ */
+
+#include <QRegularExpression>
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+#  include <QVersionNumber>
+#else /* < Qt-5.6 */
+#  include <QVector>
+#endif /* >= Qt-5.6 */
+
+#include "src/datovka_shared/app_version_info.h"
+#include "src/datovka_shared/log/log.h"
+
+/*!
+ * @brief Strip unwanted data from version string.
+ *
+ * @param[in,out] vStr Version string. Must contain a substring in format
+ *                     '[0-9]+.[0-9]+.[0-9]+' .
+ * @return True if such substring is found.
+ */
+static
+bool stripVersionString(QString &vStr)
+{
+	vStr.remove(QRegularExpression(QLatin1String("^[^0-9.]*")));
+	vStr.remove(QRegularExpression(QLatin1String("[^0-9.].*$")));
+	vStr.remove(QRegularExpression(QLatin1String("^[.]*")));
+	vStr.remove(QRegularExpression(QLatin1String("[.]*$")));
+
+	QRegularExpression verExpr(
+	    QLatin1String("[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*"));
+	QRegularExpressionMatch match(verExpr.match(vStr));
+
+	return match.hasMatch() && (match.capturedLength() == vStr.length());
+}
+
+#if (QT_VERSION < QT_VERSION_CHECK(5, 6, 0))
+#  warning "Compiling against version < Qt-5.6 which does not have QVersionNumber."
+
+/*!
+ * @brief Replacement for QVersionNumber which is not present in Qt before 5.6.
+ */
+class QVersionNumber {
+public:
+	QVersionNumber(void) : m_major(-1), m_micro(-1), m_minor(-1)
+	{
+	}
+
+	bool isNull(void) const
+	{
+		return (m_major < 0) || (m_micro < 0) || (m_minor < 0);
+	}
+
+	static
+	int compare(const QVersionNumber &v1, const QVersionNumber &v2)
+	{
+		if (v1.m_major < v2.m_major) {
+			return -1;
+		} else if (v1.m_major > v2.m_major) {
+			return 1;
+		} else if (v1.m_micro < v2.m_micro) {
+			return -1;
+		} else if (v1.m_micro > v2.m_micro) {
+			return 1;
+		} else if (v1.m_minor < v2.m_minor) {
+			return -1;
+		} else if (v1.m_minor > v2.m_minor) {
+			return 1;
+		} else {
+			return 0;
+		}
+	}
+
+	static
+	QVersionNumber fromString(const QString &str)
+	{
+		QVersionNumber verNum;
+
+		const int elemNum = 3;
+		QStringList elemList(str.split(QChar('.')));
+		if (elemList.size() != elemNum) {
+			return verNum;
+		}
+
+		QVector<int> elemVect(3, -1);
+		for (int i = 0; i < elemNum; ++i) {
+			bool ok = false;
+			elemVect[i] = elemList[i].toInt(&ok);
+			if (!ok) {
+				elemVect[i] = -1;
+			}
+		}
+
+		verNum.m_major = elemVect[0];
+		verNum.m_micro = elemVect[1];
+		verNum.m_minor = elemVect[2];
+		return verNum;
+	}
+
+private:
+	int m_major;
+	int m_micro;
+	int m_minor;
+};
+#endif
+
+int AppVersionInfo::compareVersionStrings(const QString &vStr1, const QString &vStr2)
+{
+	QString vs1(vStr1), vs2(vStr2);
+
+	if (Q_UNLIKELY(!stripVersionString(vs1))) {
+		logErrorNL("Cannot strip version string '%s'.",
+		    vs1.toUtf8().constData());
+		return -2;
+	}
+	if (Q_UNLIKELY(!stripVersionString(vs2))) {
+		logErrorNL("Cannot strip version string '%s'.",
+		    vs2.toUtf8().constData());
+		return 2;
+	}
+
+	QVersionNumber v1 = QVersionNumber::fromString(vs1);
+	if (Q_UNLIKELY(v1.isNull())) {
+		logErrorNL(
+		    "Version string '%s' doesn't match required format.",
+		    vs1.toUtf8().constData());
+		return -2;
+	}
+	QVersionNumber v2 = QVersionNumber::fromString(vs2);
+	if (Q_UNLIKELY(v2.isNull())) {
+		logErrorNL(
+		    "Version string '%s' doesn't match required format.",
+		    vs2.toUtf8().constData());
+		return 2;
+	}
+
+	/*
+	 * Documentation of QVersionNumber::compare() only mentions negative
+	 * or positive values. It doesn't mention -1 or 1.
+	 */
+	int cmp = QVersionNumber::compare(v1, v2);
+	if (cmp < 0) {
+		return -1;
+	} else if (cmp == 0) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
diff --git a/src/changelog.h b/src/datovka_shared/app_version_info.h
similarity index 57%
rename from src/changelog.h
rename to src/datovka_shared/app_version_info.h
index 6934d3127..ec832ee14 100644
--- a/src/changelog.h
+++ b/src/datovka_shared/app_version_info.h
@@ -23,18 +23,32 @@
 
 #pragma once
 
-#include <QObject>
+#include <QCoreApplication> /* Q_DECLARE_TR_FUNCTIONS */
 #include <QString>
 
-class ChangeLog : public QObject {
-    Q_OBJECT
+class AppVersionInfo {
+	Q_DECLARE_TR_FUNCTIONS(AppVersionInfo)
 
 public:
 	/*!
-	 * @brief Changelog text.
+	 * @brief Compare newest available version and application version.
 	 *
-	 * @return Changelog text.
+	 * @param[in] vStr1 Version string.
+	 * @param[in] vStr2 Version string.
+	 * @retval -2 if vStr1 doesn't contain a suitable version string
+	 * @retval -1 if vStr1 is less than vStr2
+	 * @retval  0 if vStr1 is equal to vStr2
+	 * @retval  1 if vStr1 is greater than vStr2
+	 * @retval  2 if vStr2 doesn't contain a suitable version string
 	 */
 	static
-	QString changeLogContent(void);
+	int compareVersionStrings(const QString &vStr1, const QString &vStr2);
+
+        /*!
+         * @brief Release news.
+         *
+         * @return Release news text.
+         */
+        static
+        QString releaseNewsText(void);
 };
diff --git a/src/setwrapper.cpp b/src/setwrapper.cpp
index a32978c75..6eb66cb4d 100644
--- a/src/setwrapper.cpp
+++ b/src/setwrapper.cpp
@@ -22,20 +22,20 @@
  */
 
 #include <QtGlobal> /* QT_VERSION, qVersion() */
-#include <QVersionNumber>
 
 #if defined (Q_OS_ANDROID)
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
-	#include "android_qt6/src/android_io.h"
-#else
-	#include "android/src/android_io.h"
-#endif
+#  if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
+#    include "android_qt6/src/android_io.h"
+#  else
+#    include "android/src/android_io.h"
+#  endif
 #endif
 
 #if defined (Q_OS_IOS)
-#include "ios/src/url_opener.h"
+#  include "ios/src/url_opener.h"
 #endif
 
+#include "src/datovka_shared/app_version_info.h"
 #include "src/datovka_shared/compat_qt/random.h"
 #include "src/datovka_shared/localisation/localisation.h"
 #include "src/datovka_shared/log/log.h"
@@ -45,7 +45,6 @@
 #include "src/datovka_shared/utility/date_time.h"
 #include "src/font/font.h"
 #include "src/global.h"
-#include "src/changelog.h"
 #include "src/io/filesystem.h"
 #include "src/settings/accounts.h"
 #include "src/settings/ini_preferences.h"
@@ -785,41 +784,6 @@ bool GlobalSettingsQmlWrapper::useIosDocumentPicker(void)
 	}
 }
 
-/*!
- * @brief Compare current app version and pref db version.
- *
- * @param[in] cVersion App current version string.
- * @param[in] dbVersion Pref database version string.
- * @return True if current app version is higher.
- */
-static
-bool compareVersionStrings(const QString &cVersion, const QString &dbVersion)
-{
-	QVersionNumber v1 = QVersionNumber::fromString(cVersion);
-	if (v1.isNull()) {
-		logErrorNL(
-		    "Version string '%s' does not match required format.",
-		    cVersion.toUtf8().constData());
-		return false;
-	}
-	QVersionNumber v2 = QVersionNumber::fromString(dbVersion);
-	if (v2.isNull()) {
-		logErrorNL(
-		    "Version string '%s' does not match required format.",
-		    dbVersion.toUtf8().constData());
-		return false;
-	}
-
-	int cmp = QVersionNumber::compare(v1, v2);
-	if (cmp < 0) {
-		return false;
-	} else if (cmp == 0) {
-		return false;
-	} else {
-		return true;
-	}
-}
-
 bool GlobalSettingsQmlWrapper::isNewVersion(void)
 {
 	bool isNew = true;
@@ -839,7 +803,7 @@ bool GlobalSettingsQmlWrapper::isNewVersion(void)
 		}
 	}
 
-	isNew = compareVersionStrings(VERSION, dbVersion);
+	isNew = AppVersionInfo::compareVersionStrings(VERSION, dbVersion) > 0;
 
 	if (isNew) {
 		if (GlobInstcs::prefsPtr != Q_NULLPTR) {
@@ -855,5 +819,5 @@ bool GlobalSettingsQmlWrapper::isNewVersion(void)
 
 QString GlobalSettingsQmlWrapper::loadChangeLogText(void)
 {
-	return ChangeLog::changeLogContent();
+	return AppVersionInfo::releaseNewsText();
 }
-- 
GitLab


From bc9c4c0adeff3ec503b11945a9c42829ba0d91b2 Mon Sep 17 00:00:00 2001
From: Karel Slany <karel.slany@nic.cz>
Date: Tue, 18 Feb 2025 17:42:20 +0100
Subject: [PATCH 5/9] Fixed cmakelist.

---
 CMakeLists.txt | 5 +++--
 res/qml.qrc    | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8a517c523..7c44c6b42 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,10 +19,12 @@ find_package(Qt6 REQUIRED COMPONENTS LinguistTools)
 qt_standard_project_setup(REQUIRES 6.5)
 
 qt_add_executable(mobile-datovka
+    src/app_version_info.cpp
     src/auxiliaries/email_helper.cpp src/auxiliaries/email_helper.h
     src/auxiliaries/ios_helper.cpp src/auxiliaries/ios_helper.h
     src/backup_zip.cpp src/backup_zip.h
     src/crypto/crypto.c src/crypto/crypto.h
+    src/datovka_shared/app_version_info.cpp src/datovka_shared/app_version_info.h
     src/datovka_shared/compat/compiler.h
     src/datovka_shared/compat_qt/misc.h
     src/datovka_shared/compat_qt/random.cpp src/datovka_shared/compat_qt/random.h
@@ -109,7 +111,6 @@ qt_add_executable(mobile-datovka
     src/gov_services/models/gov_form_list_model.cpp src/gov_services/models/gov_form_list_model.h
     src/gov_services/models/gov_service_list_model.cpp src/gov_services/models/gov_service_list_model.h
     src/gov_wrapper.cpp src/gov_wrapper.h
-    src/changelog.cpp src/changelog.h
     src/initialisation.cpp src/initialisation.h
     src/io/filesystem.cpp src/io/filesystem.h
     src/isds/conversion/isds_conversion.cpp src/isds/conversion/isds_conversion.h
@@ -233,13 +234,13 @@ qt_add_qml_module(mobile-datovka
         res/../qml/components/AccessibleTextInfoSmall.qml
         res/../qml/components/AccessibleToolButton.qml
         res/../qml/components/AccountList.qml
+        res/../qml/components/ChangeLogBox.qml
         res/../qml/components/ControlGroupItem.qml
         res/../qml/components/DataboxList.qml
         res/../qml/components/FileDialogue.qml
         res/../qml/components/FilterBar.qml
         res/../qml/components/GovFormList.qml
         res/../qml/components/GovServiceList.qml
-        res/../qml/components/ChangeLogBox.qml
         res/../qml/components/MessageBox.qml
         res/../qml/components/MessageList.qml
         res/../qml/components/PageHeader.qml
diff --git a/res/qml.qrc b/res/qml.qrc
index cae41eb70..8f36184fd 100644
--- a/res/qml.qrc
+++ b/res/qml.qrc
@@ -18,13 +18,13 @@
         <file>../qml/components/AccessibleTextInfoSmall.qml</file>
         <file>../qml/components/AccessibleToolButton.qml</file>
         <file>../qml/components/AccountList.qml</file>
+        <file>../qml/components/ChangeLogBox.qml</file>
         <file>../qml/components/ControlGroupItem.qml</file>
         <file>../qml/components/DataboxList.qml</file>
         <file>../qml/components/FileDialogue.qml</file>
         <file>../qml/components/FilterBar.qml</file>
         <file>../qml/components/GovFormList.qml</file>
         <file>../qml/components/GovServiceList.qml</file>
-        <file>../qml/components/ChangeLogBox.qml</file>
         <file>../qml/components/MessageBox.qml</file>
         <file>../qml/components/MessageList.qml</file>
         <file>../qml/components/PageHeader.qml</file>
-- 
GitLab


From c3a0539be241f81b7eb69f52eb24fa8129d6aabd Mon Sep 17 00:00:00 2001
From: Karel Slany <karel.slany@nic.cz>
Date: Tue, 18 Feb 2025 17:43:36 +0100
Subject: [PATCH 6/9] Removed repeated pointer checks.

---
 src/setwrapper.cpp | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/src/setwrapper.cpp b/src/setwrapper.cpp
index 6eb66cb4d..293b9c8df 100644
--- a/src/setwrapper.cpp
+++ b/src/setwrapper.cpp
@@ -787,31 +787,24 @@ bool GlobalSettingsQmlWrapper::useIosDocumentPicker(void)
 bool GlobalSettingsQmlWrapper::isNewVersion(void)
 {
 	bool isNew = true;
-	QString dbVersion;
+	QString storedVersion;
 
 	if (GlobInstcs::prefsPtr != Q_NULLPTR) {
-		GlobInstcs::prefsPtr->strVal("app.version", dbVersion);
+		GlobInstcs::prefsPtr->strVal("application.notification_shown.last_version", storedVersion);
 	} else {
 		Q_ASSERT(0);
+		return false;
 	}
-	if (Q_UNLIKELY(dbVersion.isEmpty())) {
-		if (GlobInstcs::prefsPtr != Q_NULLPTR) {
-			GlobInstcs::prefsPtr->setStrVal("app.version", VERSION);
-			return isNew;
-		} else {
-			Q_ASSERT(0);
-		}
+
+	if (Q_UNLIKELY(storedVersion.isEmpty())) {
+		GlobInstcs::prefsPtr->setStrVal("application.notification_shown.last_version", VERSION);
+		return isNew;
 	}
 
-	isNew = AppVersionInfo::compareVersionStrings(VERSION, dbVersion) > 0;
+	isNew = (1 == AppVersionInfo::compareVersionStrings(VERSION, storedVersion));
 
 	if (isNew) {
-		if (GlobInstcs::prefsPtr != Q_NULLPTR) {
-			GlobInstcs::prefsPtr->setStrVal("app.version", VERSION);
-			return isNew;
-		} else {
-			Q_ASSERT(0);
-		}
+		GlobInstcs::prefsPtr->setStrVal("application.notification_shown.last_version", VERSION);
 	}
 
 	return isNew;
-- 
GitLab


From 3234d1000f9a8eb22b37bcd8411cadae8d4e08d9 Mon Sep 17 00:00:00 2001
From: Karel Slany <karel.slany@nic.cz>
Date: Wed, 19 Feb 2025 16:25:36 +0100
Subject: [PATCH 7/9] Pulled changes from desktop application.

---
 src/datovka_shared/app_version_info.cpp | 38 +++++++++++++++++++++++--
 src/datovka_shared/app_version_info.h   | 38 ++++++++++++++++++++-----
 src/setwrapper.cpp                      | 26 +++++++++++------
 src/setwrapper.h                        |  3 ++
 4 files changed, 86 insertions(+), 19 deletions(-)

diff --git a/src/datovka_shared/app_version_info.cpp b/src/datovka_shared/app_version_info.cpp
index da5ad0a2c..66ee35067 100644
--- a/src/datovka_shared/app_version_info.cpp
+++ b/src/datovka_shared/app_version_info.cpp
@@ -31,6 +31,40 @@
 #include "src/datovka_shared/app_version_info.h"
 #include "src/datovka_shared/log/log.h"
 
+/* Release version string. */
+static const QRegularExpression releaseVerExpr(
+    QLatin1String("[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*"));
+/* Test build version string. */
+static const QRegularExpression gitAchiveVerExr(
+    QLatin1String("[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9a-f][0-9a-f]*"));
+
+/*!
+ * @brief Check whether trimmed \a str contains exactly a string matching \a re.
+ *
+ * @param[in] str String to be checked for match.
+ * @param[in] re Regular expression.
+ * @return True if trimmed \a str matches \a re.
+ */
+static inline
+bool trimmedMatchesRegExpr(const QString &str, const QRegularExpression &re)
+{
+	const QString trimmedStr = str.trimmed();
+
+	QRegularExpressionMatch match(re.match(trimmedStr));
+
+	return match.hasMatch() && (match.capturedLength() == trimmedStr.length());
+}
+
+bool AppVersionInfo::isReleaseVersionString(const QString &vStr)
+{
+	return trimmedMatchesRegExpr(vStr, releaseVerExpr);
+}
+
+bool AppVersionInfo::isGitArchiveString(const QString &vStr)
+{
+	return trimmedMatchesRegExpr(vStr, gitAchiveVerExr);
+}
+
 /*!
  * @brief Strip unwanted data from version string.
  *
@@ -46,9 +80,7 @@ bool stripVersionString(QString &vStr)
 	vStr.remove(QRegularExpression(QLatin1String("^[.]*")));
 	vStr.remove(QRegularExpression(QLatin1String("[.]*$")));
 
-	QRegularExpression verExpr(
-	    QLatin1String("[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*"));
-	QRegularExpressionMatch match(verExpr.match(vStr));
+	QRegularExpressionMatch match(releaseVerExpr.match(vStr));
 
 	return match.hasMatch() && (match.capturedLength() == vStr.length());
 }
diff --git a/src/datovka_shared/app_version_info.h b/src/datovka_shared/app_version_info.h
index ec832ee14..e7b24ebc4 100644
--- a/src/datovka_shared/app_version_info.h
+++ b/src/datovka_shared/app_version_info.h
@@ -30,6 +30,30 @@ class AppVersionInfo {
 	Q_DECLARE_TR_FUNCTIONS(AppVersionInfo)
 
 public:
+	/*!
+	 * @brief Check whether string contains only release version
+	 *     (eg. 4.25.0).
+	 *
+	 * @note The string may contain some leading and trailing white-space characters.
+	 *
+	 * @param[in] vStr Version string.
+	 * @return If \a vStr is a release version.
+	 */
+	static
+	bool isReleaseVersionString(const QString &vStr);
+
+	/*!
+	 * @brief Check whether string contains git development build version
+	 *     (eg. 4.25.0.9999.20250106.151005.ee2327675e2f1a9a).
+	 *
+	 * @note The string may contain some leading and trailing white-space characters.
+	 *
+	 * @param[in] vStr Version string.
+	 * @return If \a vStr is a git development build version.
+	 */
+	static
+	bool isGitArchiveString(const QString &vStr);
+
 	/*!
 	 * @brief Compare newest available version and application version.
 	 *
@@ -44,11 +68,11 @@ public:
 	static
 	int compareVersionStrings(const QString &vStr1, const QString &vStr2);
 
-        /*!
-         * @brief Release news.
-         *
-         * @return Release news text.
-         */
-        static
-        QString releaseNewsText(void);
+	/*!
+	 * @brief Release news.
+	 *
+	 * @return Release news text.
+	 */
+	static
+	QString releaseNewsText(void);
 };
diff --git a/src/setwrapper.cpp b/src/setwrapper.cpp
index 293b9c8df..f731a0c62 100644
--- a/src/setwrapper.cpp
+++ b/src/setwrapper.cpp
@@ -786,22 +786,30 @@ bool GlobalSettingsQmlWrapper::useIosDocumentPicker(void)
 
 bool GlobalSettingsQmlWrapper::isNewVersion(void)
 {
+	if (Q_UNLIKELY(Q_NULLPTR == GlobInstcs::prefsPtr)) {
+		Q_ASSERT(0);
+		return false;
+	}
+
 	bool isNew = true;
 	QString storedVersion;
 
-	if (GlobInstcs::prefsPtr != Q_NULLPTR) {
-		GlobInstcs::prefsPtr->strVal("application.notification_shown.last_version", storedVersion);
-	} else {
-		Q_ASSERT(0);
+	/*
+	 * If running app doesn't have release version then don't check.
+	 */
+	if (Q_UNLIKELY(!AppVersionInfo::isReleaseVersionString(VERSION))) {
 		return false;
 	}
 
-	if (Q_UNLIKELY(storedVersion.isEmpty())) {
-		GlobInstcs::prefsPtr->setStrVal("application.notification_shown.last_version", VERSION);
-		return isNew;
-	}
+	GlobInstcs::prefsPtr->strVal("application.notification_shown.last_version", storedVersion);
 
-	isNew = (1 == AppVersionInfo::compareVersionStrings(VERSION, storedVersion));
+	/*
+	 * If stored version is empty or non-release version string then behave
+	 * as having a new version.
+	 */
+	isNew = storedVersion.isEmpty()
+	    || (!AppVersionInfo::isReleaseVersionString(storedVersion))
+	    || (1 == AppVersionInfo::compareVersionStrings(VERSION, storedVersion));
 
 	if (isNew) {
 		GlobInstcs::prefsPtr->setStrVal("application.notification_shown.last_version", VERSION);
diff --git a/src/setwrapper.h b/src/setwrapper.h
index 9ac28a408..aa1a08e25 100644
--- a/src/setwrapper.h
+++ b/src/setwrapper.h
@@ -494,6 +494,9 @@ public:
 	/*!
 	 * @brief Check if new version after first startup.
 	 *
+	 * @note This check isn't performed if running app doesn't have a valid
+	 *     release version.
+	 *
 	 * @return True if it is new version after first startup.
 	*/
 	Q_INVOKABLE static
-- 
GitLab


From a5e038ba36ba13f7aca80f0232b570f7d1892aeb Mon Sep 17 00:00:00 2001
From: Karel Slany <karel.slany@nic.cz>
Date: Wed, 19 Feb 2025 17:40:37 +0100
Subject: [PATCH 8/9] Fixed some strings.

---
 qml/components/ChangeLogBox.qml |  2 +-
 qml/pages/PageAboutApp.qml      |  4 ++--
 src/app_version_info.cpp        | 12 ++++--------
 3 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/qml/components/ChangeLogBox.qml b/qml/components/ChangeLogBox.qml
index 13b0b172b..9b580a377 100644
--- a/qml/components/ChangeLogBox.qml
+++ b/qml/components/ChangeLogBox.qml
@@ -60,7 +60,7 @@ Popup {
             horizontalAlignment : Text.Center
             wrapMode: Text.Wrap
             font.bold: true
-            text: qsTr("What is news?")
+            text: qsTr("What's new?")
         }
         Rectangle {
             Layout.preferredWidth: root.preferredMinWidth
diff --git a/qml/pages/PageAboutApp.qml b/qml/pages/PageAboutApp.qml
index bc0709a58..9dd306477 100644
--- a/qml/pages/PageAboutApp.qml
+++ b/qml/pages/PageAboutApp.qml
@@ -90,8 +90,8 @@ Page {
                     }
                     AccessibleButton {
                         anchors.horizontalCenter: parent.horizontalCenter
-                        text: qsTr("Show ChangeLog")
-                        accessibleName: qsTr("What is news?")
+                        text: qsTr("Show News")
+                        accessibleName: qsTr("What's new?")
                         onClicked: changeLogBox.showChangeLog()
                     }
                     AccessibleTextInfo {
diff --git a/src/app_version_info.cpp b/src/app_version_info.cpp
index b51dee8e2..685d33104 100644
--- a/src/app_version_info.cpp
+++ b/src/app_version_info.cpp
@@ -21,22 +21,18 @@
  * the two.
  */
 
+#include <QStringBuilder>
+
 #include "src/datovka_shared/app_version_info.h"
 
 #define textLineNL(text) \
-	(QLatin1String("<style>li{margin-left:-30px;}</style><ul><li>") + (text) + QLatin1String("</li></ul>"))
+	(QLatin1String("<style>li{margin-left:-30px;}</style><ul><li>") % (text) % QLatin1String("</li></ul>"))
 
 QString AppVersionInfo::releaseNewsText(void)
 {
 	QString content;
 
-	content.append(textLineNL(tr("Added a preferences editor.")));
-	content.append(textLineNL(tr("Custom images can be assigned to individual data boxes as logos in the data-box list.")));
-	content.append(textLineNL(tr("Using dedicated redirection URL to access donation page.")));
-	content.append(textLineNL(tr("INI configuration file is written in three stages. A copy is written then the original is removed and finally the copy replaces the original.")));
-	content.append(textLineNL(tr("On application start-up when INI configuration is missing the application searches for a copy before creating a blank INI file.")));
-	content.append(textLineNL(tr("Fixed white border around launcher icon in iOS.")));
-	content.append(textLineNL(tr("Fixed logging of debug information when building with cmake.")));
+	content.append(textLineNL(tr("Showing news. :)")));
 
 	return content;
 }
-- 
GitLab


From 08da4ba80fef1e1f2872bf9e8f071f2edc0b903f Mon Sep 17 00:00:00 2001
From: Martin Straka <martin.straka@nic.cz>
Date: Thu, 20 Feb 2025 09:06:42 +0100
Subject: [PATCH 9/9] Moved changelog button into development tab.

---
 qml/pages/PageAboutApp.qml | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/qml/pages/PageAboutApp.qml b/qml/pages/PageAboutApp.qml
index 9dd306477..8d47d48ee 100644
--- a/qml/pages/PageAboutApp.qml
+++ b/qml/pages/PageAboutApp.qml
@@ -88,12 +88,6 @@ Page {
                             + "<br/>"
                             + "<a href=\"%1\">%2</a>".arg("https://datovka.nic.cz/redirect/donation-mobile.html").arg(qsTr("Make a donation."))
                     }
-                    AccessibleButton {
-                        anchors.horizontalCenter: parent.horizontalCenter
-                        text: qsTr("Show News")
-                        accessibleName: qsTr("What's new?")
-                        onClicked: changeLogBox.showChangeLog()
-                    }
                     AccessibleTextInfo {
                         horizontalAlignment: Text.AlignHCenter
                         textFormat: TextEdit.RichText
@@ -157,6 +151,12 @@ Page {
                             + "<br/>"
                             + "<a href=\"mailto:datovka@labs.nic.cz?Subject=[Mobile Datovka%20" + settings.appVersion() + "]\">datovka@labs.nic.cz</a>"
                     }
+                    AccessibleButton {
+                        anchors.horizontalCenter: parent.horizontalCenter
+                        text: qsTr("Show News")
+                        accessibleName: qsTr("What's new?")
+                        onClicked: changeLogBox.showChangeLog()
+                    }
                 } // Column
             } // Pane
         } // Flickable
-- 
GitLab