mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-05 12:07:25 +00:00
feat(wavelog): per-record Wavelog upload state (model, migration, dao, repo)
This commit is contained in:
1 parent
cbe3e50f86
commit
733f660d78
7 files changed
+54
-2
No files matched your search
@@ -47,4 +47,7 @@ interface QsoDao {
|
|||||||
|
|
||||||
@Query("UPDATE qso_records SET lotwUploaded = 1 WHERE id IN (:ids)")
|
@Query("UPDATE qso_records SET lotwUploaded = 1 WHERE id IN (:ids)")
|
||||||
suspend fun markUploaded(ids: List<Long>)
|
suspend fun markUploaded(ids: List<Long>)
|
||||||
|
|
||||||
|
@Query("UPDATE qso_records SET wavelogUploaded = 1 WHERE id IN (:ids)")
|
||||||
|
suspend fun markWavelogUploaded(ids: List<Long>)
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ import com.rtbishop.look4sat.core.data.database.entity.QsoEntity
|
|||||||
* upload receipts). Kept apart from [Look4SatDb] so existing installations
|
* upload receipts). Kept apart from [Look4SatDb] so existing installations
|
||||||
* never need a migration of the satellite database.
|
* never need a migration of the satellite database.
|
||||||
*/
|
*/
|
||||||
@Database(entities = [QsoEntity::class], version = 3, exportSchema = false)
|
@Database(entities = [QsoEntity::class], version = 4, exportSchema = false)
|
||||||
abstract class QsoDatabase : RoomDatabase() {
|
abstract class QsoDatabase : RoomDatabase() {
|
||||||
abstract fun qsoDao(): QsoDao
|
abstract fun qsoDao(): QsoDao
|
||||||
}
|
}
|
||||||
@@ -38,3 +38,10 @@ val MIGRATION_QSO_2_3 = object : Migration(2, 3) {
|
|||||||
db.execSQL("ALTER TABLE qso_records ADD COLUMN theirVuccGrids TEXT NOT NULL DEFAULT ''")
|
db.execSQL("ALTER TABLE qso_records ADD COLUMN theirVuccGrids TEXT NOT NULL DEFAULT ''")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** v3 → v4: track whether a QSO was uploaded to Wavelog (independent of the LoTW state). */
|
||||||
|
val MIGRATION_QSO_3_4 = object : Migration(3, 4) {
|
||||||
|
override fun migrate(db: SupportSQLiteDatabase) {
|
||||||
|
db.execSQL("ALTER TABLE qso_records ADD COLUMN wavelogUploaded INTEGER NOT NULL DEFAULT 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,7 @@ data class QsoEntity(
|
|||||||
@ColumnInfo(defaultValue = "''") val propagationMode: String = "",
|
@ColumnInfo(defaultValue = "''") val propagationMode: String = "",
|
||||||
@ColumnInfo(defaultValue = "0") val lotwConfirmed: Boolean = false,
|
@ColumnInfo(defaultValue = "0") val lotwConfirmed: Boolean = false,
|
||||||
@ColumnInfo(defaultValue = "0") val lotwUploaded: Boolean = false,
|
@ColumnInfo(defaultValue = "0") val lotwUploaded: Boolean = false,
|
||||||
|
@ColumnInfo(defaultValue = "0") val wavelogUploaded: Boolean = false,
|
||||||
@ColumnInfo(defaultValue = "0") val lotwReceived: Boolean = false,
|
@ColumnInfo(defaultValue = "0") val lotwReceived: Boolean = false,
|
||||||
@ColumnInfo(defaultValue = "''") val lotwQslDate: String = "",
|
@ColumnInfo(defaultValue = "''") val lotwQslDate: String = "",
|
||||||
@ColumnInfo(defaultValue = "''") val vuccGrids: String = "",
|
@ColumnInfo(defaultValue = "''") val vuccGrids: String = "",
|
||||||
|
|||||||
+10
-1
@@ -51,12 +51,14 @@ class QsoRepository(
|
|||||||
// place: that contact already exists on LoTW under the old values. The original row
|
// place: that contact already exists on LoTW under the old values. The original row
|
||||||
// keeps its upload/confirmation state, and the edited content is saved as a NEW
|
// keeps its upload/confirmation state, and the edited content is saved as a NEW
|
||||||
// record (without any LoTW state, so it can be uploaded again).
|
// record (without any LoTW state, so it can be uploaded again).
|
||||||
if (previous != null && (previous.lotwUploaded || previous.lotwConfirmed) &&
|
if (previous != null &&
|
||||||
|
(previous.lotwUploaded || previous.lotwConfirmed || previous.wavelogUploaded) &&
|
||||||
!record.sameEditableContentAs(previous)
|
!record.sameEditableContentAs(previous)
|
||||||
) {
|
) {
|
||||||
dao.save(record.copy(
|
dao.save(record.copy(
|
||||||
id = 0L,
|
id = 0L,
|
||||||
lotwUploaded = false, lotwConfirmed = false, lotwReceived = false,
|
lotwUploaded = false, lotwConfirmed = false, lotwReceived = false,
|
||||||
|
wavelogUploaded = false,
|
||||||
lotwQslDate = "", vuccGrids = emptyList(), theirVuccGrids = emptyList(),
|
lotwQslDate = "", vuccGrids = emptyList(), theirVuccGrids = emptyList(),
|
||||||
dxcc = null, country = "", cqZone = null, region = ""
|
dxcc = null, country = "", cqZone = null, region = ""
|
||||||
).toEntity())
|
).toEntity())
|
||||||
@@ -93,6 +95,11 @@ class QsoRepository(
|
|||||||
if (stamped.isNotEmpty()) dao.saveBatch(stamped.map { it.toEntity() })
|
if (stamped.isNotEmpty()) dao.saveBatch(stamped.map { it.toEntity() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun markWavelogUploaded(ids: List<Long>) = withContext(dispatcher) {
|
||||||
|
if (ids.isEmpty()) return@withContext
|
||||||
|
importMutex.withLock { dao.markWavelogUploaded(ids) }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun exportAdi(ids: Set<Long>?, includeIncomplete: Boolean): String = withContext(dispatcher) {
|
override suspend fun exportAdi(ids: Set<Long>?, includeIncomplete: Boolean): String = withContext(dispatcher) {
|
||||||
val records = dao.getAll()
|
val records = dao.getAll()
|
||||||
.asSequence()
|
.asSequence()
|
||||||
@@ -286,6 +293,7 @@ private fun QsoEntity.toDomain() = QsoRecord(
|
|||||||
propagationMode = propagationMode,
|
propagationMode = propagationMode,
|
||||||
lotwConfirmed = lotwConfirmed,
|
lotwConfirmed = lotwConfirmed,
|
||||||
lotwUploaded = lotwUploaded,
|
lotwUploaded = lotwUploaded,
|
||||||
|
wavelogUploaded = wavelogUploaded,
|
||||||
lotwReceived = lotwReceived,
|
lotwReceived = lotwReceived,
|
||||||
lotwQslDate = lotwQslDate,
|
lotwQslDate = lotwQslDate,
|
||||||
vuccGrids = vuccGrids.split(',').filter(String::isNotBlank),
|
vuccGrids = vuccGrids.split(',').filter(String::isNotBlank),
|
||||||
@@ -323,6 +331,7 @@ private fun QsoRecord.toEntity() = QsoEntity(
|
|||||||
propagationMode = propagationMode.ifBlank { if (satelliteName.isNotBlank()) "SAT" else "" },
|
propagationMode = propagationMode.ifBlank { if (satelliteName.isNotBlank()) "SAT" else "" },
|
||||||
lotwConfirmed = lotwConfirmed,
|
lotwConfirmed = lotwConfirmed,
|
||||||
lotwUploaded = lotwUploaded,
|
lotwUploaded = lotwUploaded,
|
||||||
|
wavelogUploaded = wavelogUploaded,
|
||||||
lotwReceived = lotwReceived,
|
lotwReceived = lotwReceived,
|
||||||
lotwQslDate = lotwQslDate,
|
lotwQslDate = lotwQslDate,
|
||||||
vuccGrids = vuccGrids.joinToString(","),
|
vuccGrids = vuccGrids.joinToString(","),
|
||||||
|
|||||||
+26
@@ -295,6 +295,27 @@ class QsoRepositoryTest {
|
|||||||
assertEquals(1, dao.getAll().size)
|
assertEquals(1, dao.getAll().size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun markWavelogUploaded_setsOnlyTheWavelogFlag() = runBlocking {
|
||||||
|
val id = dao.save(loggedInApp("SO-50", lotwUploaded = false).toEntity())
|
||||||
|
|
||||||
|
repository.markWavelogUploaded(listOf(id))
|
||||||
|
|
||||||
|
val row = dao.getAll().single()
|
||||||
|
assertTrue(row.wavelogUploaded)
|
||||||
|
assertFalse(row.lotwUploaded)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun save_editingAWavelogUploadedRecordCreatesANewRecord() = runBlocking {
|
||||||
|
val id = dao.save(loggedInApp("SO-50", lotwUploaded = false).copy(wavelogUploaded = true).toEntity())
|
||||||
|
|
||||||
|
repository.save(loggedInApp("SO-50", lotwUploaded = false).copy(id = id, theirCallsign = "BG5JVM"))
|
||||||
|
|
||||||
|
assertEquals(2, dao.getAll().size)
|
||||||
|
assertEquals(1, dao.getAll().count { it.wavelogUploaded })
|
||||||
|
}
|
||||||
|
|
||||||
/** A record as the log page creates it: tracker name, repeater pair, uplink band. */
|
/** A record as the log page creates it: tracker name, repeater pair, uplink band. */
|
||||||
private fun loggedInApp(satelliteName: String, lotwUploaded: Boolean) = QsoRecord(
|
private fun loggedInApp(satelliteName: String, lotwUploaded: Boolean) = QsoRecord(
|
||||||
startUtcMillis = qsoStart,
|
startUtcMillis = qsoStart,
|
||||||
@@ -355,6 +376,7 @@ class QsoRepositoryTest {
|
|||||||
propagationMode = propagationMode,
|
propagationMode = propagationMode,
|
||||||
lotwConfirmed = lotwConfirmed,
|
lotwConfirmed = lotwConfirmed,
|
||||||
lotwUploaded = lotwUploaded,
|
lotwUploaded = lotwUploaded,
|
||||||
|
wavelogUploaded = wavelogUploaded,
|
||||||
lotwReceived = lotwReceived,
|
lotwReceived = lotwReceived,
|
||||||
lotwQslDate = lotwQslDate,
|
lotwQslDate = lotwQslDate,
|
||||||
vuccGrids = vuccGrids.joinToString(","),
|
vuccGrids = vuccGrids.joinToString(","),
|
||||||
@@ -393,5 +415,9 @@ class QsoRepositoryTest {
|
|||||||
override suspend fun markUploaded(ids: List<Long>) {
|
override suspend fun markUploaded(ids: List<Long>) {
|
||||||
ids.forEach { id -> rows[id]?.let { rows[id] = it.copy(lotwUploaded = true) } }
|
ids.forEach { id -> rows[id]?.let { rows[id] = it.copy(lotwUploaded = true) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun markWavelogUploaded(ids: List<Long>) {
|
||||||
|
ids.forEach { id -> rows[id]?.let { rows[id] = it.copy(wavelogUploaded = true) } }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,10 @@ interface IQsoRepository {
|
|||||||
* logbook row can show which grids the QSO went out under.
|
* logbook row can show which grids the QSO went out under.
|
||||||
*/
|
*/
|
||||||
suspend fun markUploaded(ids: List<Long>, grids: List<String> = emptyList())
|
suspend fun markUploaded(ids: List<Long>, grids: List<String> = emptyList())
|
||||||
|
|
||||||
|
/** Marks the batch as uploaded to Wavelog (independent of the LoTW upload state). */
|
||||||
|
suspend fun markWavelogUploaded(ids: List<Long>)
|
||||||
|
|
||||||
suspend fun exportAdi(ids: Set<Long>? = null, includeIncomplete: Boolean = false): String
|
suspend fun exportAdi(ids: Set<Long>? = null, includeIncomplete: Boolean = false): String
|
||||||
suspend fun importAdi(content: String): AdifImportResult
|
suspend fun importAdi(content: String): AdifImportResult
|
||||||
suspend fun mergeConfirmed(records: List<QsoRecord>): AdifImportResult
|
suspend fun mergeConfirmed(records: List<QsoRecord>): AdifImportResult
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ data class QsoRecord(
|
|||||||
val propagationMode: String = if (satelliteName.isNotBlank()) "SAT" else "",
|
val propagationMode: String = if (satelliteName.isNotBlank()) "SAT" else "",
|
||||||
val lotwConfirmed: Boolean = false,
|
val lotwConfirmed: Boolean = false,
|
||||||
val lotwUploaded: Boolean = false,
|
val lotwUploaded: Boolean = false,
|
||||||
|
/** Internal: set after a successful Wavelog upload; keeps the pending filter small. Not shown in any list. */
|
||||||
|
val wavelogUploaded: Boolean = false,
|
||||||
val lotwReceived: Boolean = false,
|
val lotwReceived: Boolean = false,
|
||||||
val lotwQslDate: String = "",
|
val lotwQslDate: String = "",
|
||||||
val vuccGrids: List<String> = emptyList(),
|
val vuccGrids: List<String> = emptyList(),
|
||||||
|
|||||||
Reference in new issue
Block a user