diff --git a/qml/js/tides.js b/qml/js/tides.js
index 93316e1..2a3b2e0 100644
--- a/qml/js/tides.js
+++ b/qml/js/tides.js
@@ -168,6 +168,19 @@ function fmtHM(t) {
return (hh < 10 ? "0" : "") + hh + ":" + (mm < 10 ? "0" : "") + mm;
}
+// Scala Douglas (stato del mare) dall'altezza d'onda significativa in metri
+// 0 Calmo, 1 Quasi calmo, 2 Poco mosso, 3 Mosso, 4 Molto mosso, 5 Agitato,
+// 6 Molto agitato, 7 Grosso, 8 Molto grosso, 9 Tempestoso
+function douglas(h) {
+ if (h <= 0) return 0;
+ var soglie = [0.1, 0.5, 1.25, 2.5, 4, 6, 9, 14];
+ var g = 1;
+ for (var i = 0; i < soglie.length; i++) {
+ if (h >= soglie[i]) g++;
+ }
+ return g;
+}
+
// Formato data breve
function fmtDate(t, dn) {
var d = new Date(t);
diff --git a/qml/pages/DetailPage.qml b/qml/pages/DetailPage.qml
index 3e5f500..4bcea53 100644
--- a/qml/pages/DetailPage.qml
+++ b/qml/pages/DetailPage.qml
@@ -91,11 +91,71 @@ Page {
curveInfo.text = qsTr("Z₀ %1 m · 7 harmonic constituents").arg(port[4][0].toFixed(2))
}
cv.requestPaint()
+ seaState()
} catch (e) {
console.log("[tide] refresh error:", e)
}
}
+ function seaFail() {
+ seaLabel.text = qsTranslate("Sea", "Unavailable (offline)")
+ seaLabel.color = Theme.secondaryColor
+ seaSub.text = ""
+ }
+
+ function seaState() {
+ if (!port) return
+ console.log("[tide] seaState fetch:", port[0])
+ var xhr = new XMLHttpRequest()
+ var done = false
+ var to = setTimeout(function() {
+ if (!done) {
+ done = true
+ console.log("[tide] seaState timeout")
+ seaFail()
+ }
+ }, 12000)
+ xhr.open("GET",
+ "https://marine-api.open-meteo.com/v1/marine?latitude=" + port[2]
+ + "&longitude=" + port[3]
+ + "&daily=wave_height_max&timezone=auto&forecast_days=3",
+ true)
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ if (done) return
+ done = true
+ clearTimeout(to)
+ console.log("[tide] seaState status:", xhr.status)
+ if (xhr.status === 200) {
+ try {
+ var j = JSON.parse(xhr.responseText)
+ var wh = j.daily.wave_height_max
+ if (wh && wh.length > 0) {
+ var today = wh[0]
+ var i0 = Tides.douglas(today)
+ seaLabel.text = seaNames[i0] + " · " + Tides.fmtH(today, page.unit)
+ seaLabel.color = i0 >= 5 ? Theme.errorColor
+ : (i0 >= 4 ? Theme.secondaryColor : Theme.highlightColor)
+ if (wh.length > 1) {
+ var i1 = Tides.douglas(wh[1])
+ seaSub.text = qsTranslate("Sea", "Tomorrow") + ": " + seaNames[i1]
+ + " · " + Tides.fmtH(wh[1], page.unit)
+ seaSub.color = Theme.secondaryColor
+ } else {
+ seaSub.text = ""
+ }
+ return
+ }
+ } catch (e) {
+ console.log("[tide] seaState parse err:", e)
+ }
+ }
+ seaFail()
+ }
+ }
+ xhr.send()
+ }
+
property var moonNames: [
qsTr("New moon"), qsTr("Waxing crescent"), qsTr("First quarter"), qsTr("Waxing gibbous"),
qsTr("Full moon"), qsTr("Waning gibbous"), qsTr("Last quarter"), qsTr("Waning crescent")
@@ -109,6 +169,16 @@ Page {
qsTranslate("Tide", "Sat")
]
+ // stato del mare: scala Douglas (0-9) — context "Sea" separato:
+ // "High" qui = "Grosso", non "Alta" degli eventi
+ property var seaNames: [
+ qsTranslate("Sea", "Calm"), qsTranslate("Sea", "Calm rippled"),
+ qsTranslate("Sea", "Smooth wavelets"), qsTranslate("Sea", "Slight"),
+ qsTranslate("Sea", "Moderate"), qsTranslate("Sea", "Rough"),
+ qsTranslate("Sea", "Very rough"), qsTranslate("Sea", "High"),
+ qsTranslate("Sea", "Very high"), qsTranslate("Sea", "Phenomenal")
+ ]
+
SilicaFlickable {
id: flick
anchors.fill: parent
@@ -297,6 +367,15 @@ Page {
Label { id: rangeLabel; anchors.right: parent.right; anchors.rightMargin: Theme.horizontalPageMargin; anchors.verticalCenter: parent.verticalCenter }
}
+ // Stato del mare (scala Douglas, previsione onde Open-Meteo)
+ Item { width: parent.width; height: Theme.itemSizeSmall
+ Label { text: "🌊 " + qsTranslate("Sea", "Sea state"); color: Theme.secondaryColor; anchors.left: parent.left; anchors.leftMargin: Theme.horizontalPageMargin; anchors.verticalCenter: parent.verticalCenter }
+ Label { id: seaLabel; text: "…"; anchors.left: parent.left; anchors.leftMargin: Theme.horizontalPageMargin + 130; anchors.right: parent.right; anchors.rightMargin: Theme.horizontalPageMargin; anchors.verticalCenter: parent.verticalCenter; horizontalAlignment: Text.AlignRight; truncationMode: TruncationMode.Fade }
+ }
+ Item { width: parent.width; height: Theme.itemSizeSmall
+ Label { id: seaSub; anchors.left: parent.left; anchors.leftMargin: Theme.horizontalPageMargin + 130; anchors.right: parent.right; anchors.rightMargin: Theme.horizontalPageMargin; anchors.verticalCenter: parent.verticalCenter; horizontalAlignment: Text.AlignRight; font.pixelSize: Theme.fontSizeSmall; truncationMode: TruncationMode.Fade }
+ }
+
Item { width: parent.width; height: Theme.paddingLarge }
}
}
diff --git a/translations/harbour-tide.ts b/translations/harbour-tide.ts
index 03ad9dc..d153ba5 100644
--- a/translations/harbour-tide.ts
+++ b/translations/harbour-tide.ts
@@ -84,4 +84,20 @@
Fri
Sat
+
+ Sea
+ Calm
+ Calm rippled
+ Smooth wavelets
+ Slight
+ Moderate
+ Rough
+ Very rough
+ High
+ Very high
+ Phenomenal
+ Sea state
+ Tomorrow
+ Unavailable (offline)
+
diff --git a/translations/harbour-tide_it.ts b/translations/harbour-tide_it.ts
index 61e43fc..dba5551 100644
--- a/translations/harbour-tide_it.ts
+++ b/translations/harbour-tide_it.ts
@@ -84,4 +84,20 @@
FriVen
SatSab
+
+ Sea
+ CalmCalmo
+ Calm rippledQuasi calmo
+ Smooth waveletsPoco mosso
+ SlightMosso
+ ModerateMolto mosso
+ RoughAgitato
+ Very roughMolto agitato
+ HighGrosso
+ Very highMolto grosso
+ PhenomenalTempestoso
+ Sea stateStato del mare
+ TomorrowDomani
+ Unavailable (offline)Non disponibile (offline)
+