diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt index 31d6e98e..b76b5dfe 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/LoTWRepository.kt @@ -169,6 +169,7 @@ class LoTWRepository : ILoTWRepository { var country: String? = null var cqz: Int? = null var state: String? = null + var myGrid: String? = null val gridsInRecord = mutableListOf() fun emitRecord() { @@ -177,7 +178,8 @@ class LoTWRepository : ILoTWRepository { val qso = com.rtbishop.look4sat.core.domain.model.GridQso( call = call, epochMs = epochMs, satName = satName, mode = mode, bandUp = bandUp, bandDown = bandDown, - dxcc = dxcc, country = country, cqz = cqz, state = state + dxcc = dxcc, country = country, cqz = cqz, state = state, + myGrid = myGrid ) for (grid in gridsInRecord) { result.getOrPut(grid) { mutableListOf() }.add(qso) @@ -188,6 +190,7 @@ class LoTWRepository : ILoTWRepository { propMode = null; call = ""; qsoDate = ""; timeOn = "" satName = ""; mode = ""; bandUp = ""; bandDown = "" dxcc = null; country = null; cqz = null; state = null + myGrid = null gridsInRecord.clear() } @@ -222,6 +225,13 @@ class LoTWRepository : ILoTWRepository { cqz = adifValue(line).toIntOrNull() line.startsWith(" state = adifValue(line).trim().ifBlank { null }?.let { normalizeState(it) } + line.startsWith(" { + // Own-station grid (must not be confused with GRIDSQUARE — + // the opposite station's grid). Recorded per QSO so awards + // can be counted per operated grid. + val value = adifValue(line) + if (value.length >= 4) myGrid = value.take(4).uppercase() + } line.startsWith(" { // VUCC_GRIDS holds a comma-separated list of grids // ("EN52en,EN53fa"), up to four for contacts spanning diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SettingsRepo.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SettingsRepo.kt index a0490663..1a719925 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SettingsRepo.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/repository/SettingsRepo.kt @@ -204,7 +204,9 @@ class SettingsRepo( dxcc = o.optInt("dx", 0).takeIf { it > 0 }, country = o.optString("cty").ifBlank { null }, cqz = o.optInt("cq", 0).takeIf { it > 0 }, - state = o.optString("st").ifBlank { null } + state = o.optString("st").ifBlank { null }, + // Own-grid field: absent in pre-myGrid data -> null. + myGrid = o.optString("mg").ifBlank { null } ) } if (list.isNotEmpty()) result[grid] = list @@ -232,6 +234,7 @@ class SettingsRepo( .put("cty", q.country ?: "") .put("cq", q.cqz ?: 0) .put("st", q.state ?: "") + .put("mg", q.myGrid ?: "") ) } root.put(grid, array) diff --git a/core/data/src/test/java/com/rtbishop/look4sat/core/data/repository/LoTWRepositoryTest.kt b/core/data/src/test/java/com/rtbishop/look4sat/core/data/repository/LoTWRepositoryTest.kt index 7e59a335..b1c6f54f 100644 --- a/core/data/src/test/java/com/rtbishop/look4sat/core/data/repository/LoTWRepositoryTest.kt +++ b/core/data/src/test/java/com/rtbishop/look4sat/core/data/repository/LoTWRepositoryTest.kt @@ -3,6 +3,7 @@ package com.rtbishop.look4sat.core.data.repository import com.rtbishop.look4sat.core.domain.repository.LoTWResult import org.junit.Assert.assertEquals import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue import org.junit.Test class LoTWRepositoryTest { @@ -150,6 +151,24 @@ class LoTWRepositoryTest { assertNull(repo.parseConfirmedGridQsos("Username/password incorrect")) } + @Test + fun parseQsosCapturesOwnGridPerQso() { + // MY_GRIDSQUARE arrives BEFORE PROP_MODE (ADIF fields are emitted + // alphabetically); the per-record buffer must still attach it to the QSO. + val qso1 = "A50QO\n20260820\nOL62\n" + + "SAT\nFO-29\nCW\n" + + "70CM\n2M\nNL47\n\n" + val qso2 = "BG7ZFK\n20260819\nOL72\n" + + "SAT\nSO-50\nFM\n" + + "70CM\n2M\nOK48\n\n" + val result = repo.parseConfirmedGridQsos(report(qso1, qso2))!! + assertEquals("OL62", result["NL47"]!!.first().myGrid) + assertEquals("OL72", result["OK48"]!!.first().myGrid) + // Ground QSO (no PROP_MODE=SAT) must not leak its MY_GRIDSQUARE. + val ground = "BA7OPF\n20260821\nOL62\nNL47\n\n" + assertTrue(repo.parseConfirmedGridQsos(report(qso1, ground))!!.values.all { it.all { q -> q.myGrid == "OL62" } }) + } + // endregion // region parseRoamedGrids (MY_GRIDSQUARE = grids the account operated from) diff --git a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/model/GridQso.kt b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/model/GridQso.kt index b6717a7b..50569c5b 100644 --- a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/model/GridQso.kt +++ b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/model/GridQso.kt @@ -48,7 +48,9 @@ data class GridQso( val dxcc: Int? = null, val country: String? = null, val cqz: Int? = null, - val state: String? = null + val state: String? = null, + /** 4-char grid the station itself operated from (ADIF MY_GRIDSQUARE). */ + val myGrid: String? = null ) { /** Short uplink/downlink band label ("U/V", "V/A"), or "" when unknown. */ val bandLabel: String