diff --git a/core/ui/src/commonMain/composeResources/values-es/strings.xml b/core/ui/src/commonMain/composeResources/values-es/strings.xml
index 3abed1b64a..565f51e2da 100644
--- a/core/ui/src/commonMain/composeResources/values-es/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values-es/strings.xml
@@ -35,4 +35,5 @@
Recolector de datos
Reintentar
Área
+ Fecha
diff --git a/core/ui/src/commonMain/composeResources/values-fr/strings.xml b/core/ui/src/commonMain/composeResources/values-fr/strings.xml
index 494efb2670..05def581f7 100644
--- a/core/ui/src/commonMain/composeResources/values-fr/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values-fr/strings.xml
@@ -34,4 +34,5 @@
Collecteur de données
Réessayer
Surface
+ Date
diff --git a/core/ui/src/commonMain/composeResources/values-km/strings.xml b/core/ui/src/commonMain/composeResources/values-km/strings.xml
index cebda33d83..1d3a0a7d55 100644
--- a/core/ui/src/commonMain/composeResources/values-km/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values-km/strings.xml
@@ -34,4 +34,5 @@
អ្នកប្រមូលទិន្នន័យ
ព្យាយាមឡើងវិញ
ផ្ទៃក្រឡា
+ កាលបរិច្ឆេទ
\ No newline at end of file
diff --git a/core/ui/src/commonMain/composeResources/values-lo/strings.xml b/core/ui/src/commonMain/composeResources/values-lo/strings.xml
index f75d581416..ef6349c873 100644
--- a/core/ui/src/commonMain/composeResources/values-lo/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values-lo/strings.xml
@@ -34,4 +34,5 @@
ຜູ້ເກັບຂໍ້ມູນ
ລອງໃໝ່
ພື້ນທີ່
+ ວັນທີ
diff --git a/core/ui/src/commonMain/composeResources/values-pt/strings.xml b/core/ui/src/commonMain/composeResources/values-pt/strings.xml
index 43b8a31e2a..90829b8ad0 100644
--- a/core/ui/src/commonMain/composeResources/values-pt/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values-pt/strings.xml
@@ -35,4 +35,5 @@
Coletor de dados
Tentar novamente
Área
+ Data
diff --git a/core/ui/src/commonMain/composeResources/values-th/strings.xml b/core/ui/src/commonMain/composeResources/values-th/strings.xml
index f940fce439..840394334a 100644
--- a/core/ui/src/commonMain/composeResources/values-th/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values-th/strings.xml
@@ -34,4 +34,5 @@
ผู้เก็บข้อมูล
ลองใหม่
พื้นที่
+ วันที่
diff --git a/core/ui/src/commonMain/composeResources/values-vi/strings.xml b/core/ui/src/commonMain/composeResources/values-vi/strings.xml
index d613d1f978..fb12450c9d 100644
--- a/core/ui/src/commonMain/composeResources/values-vi/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values-vi/strings.xml
@@ -34,4 +34,5 @@
Người thu thập dữ liệu
Thử lại
Diện tích
+ Ngày
diff --git a/core/ui/src/commonMain/composeResources/values/strings.xml b/core/ui/src/commonMain/composeResources/values/strings.xml
index dfb3242e65..70ac154d55 100644
--- a/core/ui/src/commonMain/composeResources/values/strings.xml
+++ b/core/ui/src/commonMain/composeResources/values/strings.xml
@@ -35,4 +35,5 @@
Data collector
Retry
Area
+ Date
diff --git a/feature/pdf/src/androidHostTest/kotlin/org/groundplatform/feature/pdf/render/PdfWriterTest.kt b/feature/pdf/src/androidHostTest/kotlin/org/groundplatform/feature/pdf/render/PdfWriterTest.kt
index c8ab98a852..8674e25ff0 100644
--- a/feature/pdf/src/androidHostTest/kotlin/org/groundplatform/feature/pdf/render/PdfWriterTest.kt
+++ b/feature/pdf/src/androidHostTest/kotlin/org/groundplatform/feature/pdf/render/PdfWriterTest.kt
@@ -86,12 +86,21 @@ class PdfWriterTest {
}
@Test
- fun `draws the header values on the page`() {
+ fun `draws the survey, submission and date columns in the header`() {
val canvas = renderDocument(SINGLE_PAGE_DOCUMENT)
- assertTrue(canvas.drawnText.contains(HEADER.surveyName))
- assertTrue(canvas.drawnText.contains(HEADER.jobName))
- assertTrue(canvas.drawnText.contains(HEADER.timestamp))
+ assertTrue(canvas.drawnText.containsAll(listOf(HEADER.surveyLabel, HEADER.surveyName)))
+ assertTrue(canvas.drawnText.containsAll(listOf(HEADER.submissionLabel, HEADER.submissionName)))
+ assertTrue(canvas.drawnText.containsAll(listOf(HEADER.dateLabel, HEADER.timestamp)))
+ }
+
+ @Test
+ fun `draws the submission title above the table with the job below it`() {
+ val canvas = renderDocument(SINGLE_PAGE_DOCUMENT)
+
+ val jobLineIndex = canvas.drawnText.indexOf("${TABLE.jobLabel}: ${TABLE.jobName}")
+ assertTrue(jobLineIndex > 0)
+ assertEquals("${TABLE.submissionLabel}: ${TABLE.loiName}", canvas.drawnText[jobLineIndex - 1])
}
@Test
@@ -215,7 +224,7 @@ class PdfWriterTest {
val canvas = renderDocument(tableless, pdfImageSet(qr = pdfImage()))
assertEquals(listOf(1), canvas.startedPageNumbers)
- assertFalse(canvas.drawnText.contains(TABLE.submissionLabel))
+ assertFalse(canvas.drawnText.contains("${TABLE.submissionLabel}: ${TABLE.loiName}"))
}
private fun renderDocument(
@@ -269,8 +278,9 @@ class PdfWriterTest {
SubmissionPdfDocument.Header(
surveyLabel = "Survey",
surveyName = "Survey name",
- jobLabel = "Job",
- jobName = "Job name",
+ submissionLabel = "Submission",
+ submissionName = "Submission name",
+ dateLabel = "Date",
timestamp = "timestamp",
)
val FOOTER =
@@ -285,7 +295,9 @@ class PdfWriterTest {
val TABLE =
SubmissionPdfDocument.Table(
submissionLabel = "Submission",
- loiName = "Plot 42",
+ loiName = "Submission name",
+ jobLabel = "Job",
+ jobName = "Job name",
rows = emptyList(),
)
diff --git a/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfTextPaints.kt b/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfTextPaints.kt
index b41fef74c6..22ae336fbb 100644
--- a/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfTextPaints.kt
+++ b/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfTextPaints.kt
@@ -23,7 +23,7 @@ import org.groundplatform.feature.pdf.render.PdfConfig.CAPTION_SIZE
import org.groundplatform.feature.pdf.render.PdfConfig.TITLE_SIZE
internal class PdfTextPaints {
- val title: TextPaint = textPaint(TITLE_SIZE, bold = false)
+ val title: TextPaint = textPaint(TITLE_SIZE, bold = true)
val body: TextPaint = textPaint(BODY_SIZE, bold = false)
val bodyLabel: TextPaint = textPaint(BODY_SIZE, bold = true)
val metaLabel: TextPaint = textPaint(CAPTION_SIZE, bold = true, textColor = Color.GRAY)
diff --git a/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfWriter.kt b/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfWriter.kt
index f11adcb4d5..1b29890f66 100644
--- a/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfWriter.kt
+++ b/feature/pdf/src/androidMain/kotlin/org/groundplatform/feature/pdf/render/PdfWriter.kt
@@ -108,20 +108,19 @@ internal class PdfWriter(
private fun drawTable(table: SubmissionPdfDocument.Table) {
val rows = table.rows.takeIf { it.isNotEmpty() } ?: return
pageController.ensurePage()
- val label =
- SpannableString("${table.submissionLabel}: ${table.loiName}").apply {
- setSpan(
- StyleSpan(Typeface.BOLD),
- 0,
- table.submissionLabel.length,
- Spanned.SPAN_INCLUSIVE_EXCLUSIVE,
- )
- }
- val labelLayout = staticLayout(label, paints.title, USABLE_WIDTH)
- val tableLabel =
- TableLayout.getLabel(top = cursor.y, labelHeight = labelLayout.height.toFloat())
- drawStaticLayoutAt(labelLayout, tableLabel.labelOffset)
- cursor.moveTo(tableLabel.nextCursorY)
+ val titleLayout =
+ staticLayout("${table.submissionLabel}: ${table.loiName}", paints.title, USABLE_WIDTH)
+ val subtitleLayout =
+ staticLayout(labeled(table.jobLabel, table.jobName), paints.body, USABLE_WIDTH)
+ val titleBlock =
+ TableLayout.getTitleBlock(
+ top = cursor.y,
+ titleHeight = titleLayout.height.toFloat(),
+ subtitleHeight = subtitleLayout.height.toFloat(),
+ )
+ drawStaticLayoutAt(titleLayout, titleBlock.titleOffset)
+ drawStaticLayoutAt(subtitleLayout, titleBlock.subtitleOffset)
+ cursor.moveTo(titleBlock.nextCursorY)
rows.forEach { row ->
when (val answer = row.answer) {
is Answer.Text ->
@@ -154,16 +153,28 @@ internal class PdfWriter(
maxWidth = columnWidth,
maxLines = PageHeaderLayout.MAX_LINES,
)
- val jobLabel =
- staticLayout(header.jobLabel, paints.metaLabel, columnWidth, Layout.Alignment.ALIGN_CENTER)
- val jobValue =
+ val submissionLabel =
+ staticLayout(
+ header.submissionLabel,
+ paints.metaLabel,
+ columnWidth,
+ Layout.Alignment.ALIGN_CENTER,
+ )
+ val submissionValue =
staticLayout(
- text = header.jobName,
+ text = header.submissionName,
paint = paints.meta,
maxWidth = columnWidth,
alignment = Layout.Alignment.ALIGN_CENTER,
maxLines = PageHeaderLayout.MAX_LINES,
)
+ val dateLabel =
+ staticLayout(
+ header.dateLabel,
+ paints.metaLabel,
+ columnWidth,
+ Layout.Alignment.ALIGN_OPPOSITE,
+ )
val timestamp =
staticLayout(
text = header.timestamp,
@@ -182,9 +193,10 @@ internal class PdfWriter(
drawStaticLayoutAt(surveyLabel, layout.leftColumn.labelOffset)
drawStaticLayoutAt(surveyValue, layout.leftColumn.valueOffset)
- drawStaticLayoutAt(jobLabel, layout.centerColumn.labelOffset)
- drawStaticLayoutAt(jobValue, layout.centerColumn.valueOffset)
- drawStaticLayoutAt(timestamp, layout.rightTextOffset)
+ drawStaticLayoutAt(submissionLabel, layout.centerColumn.labelOffset)
+ drawStaticLayoutAt(submissionValue, layout.centerColumn.valueOffset)
+ drawStaticLayoutAt(dateLabel, layout.rightColumn.labelOffset)
+ drawStaticLayoutAt(timestamp, layout.rightColumn.valueOffset)
cursor.moveTo(layout.nextCursorY)
}
diff --git a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapper.kt b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapper.kt
index c238338aec..e8c88c1b41 100644
--- a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapper.kt
+++ b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapper.kt
@@ -17,6 +17,7 @@ package org.groundplatform.feature.pdf.mapper
import ground_android.core.ui.generated.resources.Res
import ground_android.core.ui.generated.resources.area
+import ground_android.core.ui.generated.resources.date
import ground_android.core.ui.generated.resources.job
import ground_android.core.ui.generated.resources.pdf_data_collector
import ground_android.core.ui.generated.resources.scan_this_qr_to_download_geojson
@@ -51,13 +52,15 @@ class LoiReportMapper(
val rows = buildRows(submission)
val document =
SubmissionPdfDocument(
- header = buildHeader(details, submission),
+ header = buildHeader(details, loiReport.loiName, submission),
qrBlock = buildQrBlock(loiReport.loiName),
footer = buildFooter(details),
table =
Table(
submissionLabel = strings.resolve(Res.string.submission),
loiName = loiReport.loiName,
+ jobLabel = strings.resolve(Res.string.job),
+ jobName = submission.jobName(),
rows = rows,
),
mapBlock = buildMapBlock(details),
@@ -81,18 +84,22 @@ class LoiReportMapper(
private suspend fun buildHeader(
details: LoiReport.SubmissionDetails,
+ loiName: String,
submission: Submission,
): Header =
Header(
surveyLabel = strings.resolve(Res.string.survey),
surveyName = details.surveyName,
- jobLabel = strings.resolve(Res.string.job),
- jobName = submission.job.name ?: submission.job.id,
+ submissionLabel = strings.resolve(Res.string.submission),
+ submissionName = loiName,
+ dateLabel = strings.resolve(Res.string.date),
timestamp =
"${dateFormatter.formatDate(submission.lastModified.clientTimestamp)} " +
dateFormatter.formatTime(submission.lastModified.clientTimestamp),
)
+ private fun Submission.jobName(): String = job.name ?: job.id
+
private suspend fun buildQrBlock(loiName: String): QrBlock =
QrBlock(
submissionName = loiName,
diff --git a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/model/SubmissionPdfDocument.kt b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/model/SubmissionPdfDocument.kt
index 8c6ad09f37..c4fa280bcc 100644
--- a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/model/SubmissionPdfDocument.kt
+++ b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/model/SubmissionPdfDocument.kt
@@ -33,14 +33,21 @@ data class SubmissionPdfDocument(
data class Header(
val surveyLabel: String,
val surveyName: String,
- val jobLabel: String,
- val jobName: String,
+ val submissionLabel: String,
+ val submissionName: String,
+ val dateLabel: String,
val timestamp: String,
)
data class QrBlock(val submissionName: String, val scanCaption: String)
- data class Table(val submissionLabel: String, val loiName: String, val rows: List)
+ data class Table(
+ val submissionLabel: String,
+ val loiName: String,
+ val jobLabel: String,
+ val jobName: String,
+ val rows: List,
+ )
data class Row(val question: String, val answer: Answer)
diff --git a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/PdfConfig.kt b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/PdfConfig.kt
index de80b58557..55583507c6 100644
--- a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/PdfConfig.kt
+++ b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/PdfConfig.kt
@@ -44,7 +44,7 @@ internal object PdfConfig {
const val MARGIN = 40
/** Font size for title text. */
- const val TITLE_SIZE = 11f
+ const val TITLE_SIZE = 13f
/** Font size body and table-cell text. */
const val BODY_SIZE = 11f
diff --git a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayout.kt b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayout.kt
index 9e061827a7..5b7ba4db4a 100644
--- a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayout.kt
+++ b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayout.kt
@@ -26,13 +26,13 @@ import org.groundplatform.feature.pdf.render.PdfOffset
*
* @param leftColumn Label and value positions for the left column.
* @param centerColumn Label and value positions for the center column.
- * @param rightTextOffset The position where the right-aligned value begins .
+ * @param rightColumn Label and value positions for the right column, whose text is right-aligned.
* @param nextCursorY The Y position where the cursor should be positioned after the header.
*/
internal data class PageHeaderLayout(
val leftColumn: Column,
val centerColumn: Column,
- val rightTextOffset: PdfOffset,
+ val rightColumn: Column,
val nextCursorY: Float,
) {
companion object {
@@ -53,7 +53,7 @@ internal data class PageHeaderLayout(
return PageHeaderLayout(
leftColumn = column(LEFT_X, top, labelHeight),
centerColumn = column(CENTER_X, top, labelHeight),
- rightTextOffset = PdfOffset(RIGHT_X, top),
+ rightColumn = column(RIGHT_X, top, labelHeight),
nextCursorY = columnBottom + BOTTOM_GAP,
)
}
diff --git a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayout.kt b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayout.kt
index 8d044b3e34..023187fd52 100644
--- a/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayout.kt
+++ b/feature/pdf/src/commonMain/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayout.kt
@@ -83,13 +83,26 @@ internal object TableLayout {
)
}
- data class Label(val labelOffset: PdfOffset, val nextCursorY: Float)
-
- fun getLabel(top: Float, labelHeight: Float): Label {
- val labelTop = top + LINE_SPACING * 2
- return Label(
- labelOffset = PdfOffset(MARGIN.toFloat(), labelTop),
- nextCursorY = labelTop + labelHeight + LINE_SPACING,
+ /**
+ * Layout of the two title lines above the table.
+ *
+ * @param titleOffset Top-left position of the submission line.
+ * @param subtitleOffset Top-left position of the job line, directly below the submission line.
+ * @param nextCursorY Cursor Y position after the title block.
+ */
+ data class TitleBlock(
+ val titleOffset: PdfOffset,
+ val subtitleOffset: PdfOffset,
+ val nextCursorY: Float,
+ )
+
+ fun getTitleBlock(top: Float, titleHeight: Float, subtitleHeight: Float): TitleBlock {
+ val titleTop = top + LINE_SPACING * 2
+ val subtitleTop = titleTop + titleHeight + LINE_SPACING
+ return TitleBlock(
+ titleOffset = PdfOffset(MARGIN.toFloat(), titleTop),
+ subtitleOffset = PdfOffset(MARGIN.toFloat(), subtitleTop),
+ nextCursorY = subtitleTop + subtitleHeight + LINE_SPACING * 2,
)
}
diff --git a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/PdfExportServiceTest.kt b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/PdfExportServiceTest.kt
index 51fbddb925..73c8a6f98e 100644
--- a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/PdfExportServiceTest.kt
+++ b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/PdfExportServiceTest.kt
@@ -104,8 +104,9 @@ class PdfExportServiceTest {
SubmissionPdfDocument.Header(
surveyLabel = "Survey",
surveyName = "Survey name",
- jobLabel = "Job",
- jobName = "Job name",
+ submissionLabel = "Submission",
+ submissionName = "Loi",
+ dateLabel = "Date",
timestamp = "timestamp",
),
qrBlock = SubmissionPdfDocument.QrBlock(submissionName = "Loi", scanCaption = "Scan"),
@@ -119,6 +120,8 @@ class PdfExportServiceTest {
SubmissionPdfDocument.Table(
submissionLabel = "Submission",
loiName = "Loi",
+ jobLabel = "Job",
+ jobName = "Job name",
rows = emptyList(),
),
mapBlock = null,
diff --git a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapperTest.kt b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapperTest.kt
index 1041880f56..3b8bbc73fb 100644
--- a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapperTest.kt
+++ b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/mapper/LoiReportMapperTest.kt
@@ -176,6 +176,48 @@ class LoiReportMapperTest {
assertEquals("scan_this_qr_to_download_geojson", qrBlock.scanCaption)
}
+ @Test
+ fun `header carries the survey, the submission name and the labelled date`() = runTest {
+ val report =
+ FakeDataGenerator.newLoiReport(
+ loiName = "Loi",
+ submissionDetails = FakeDataGenerator.newSubmissionDetails(surveyName = "Survey"),
+ )
+
+ val header = mapper.map(report, submission)!!.document.header
+
+ assertEquals("survey", header.surveyLabel)
+ assertEquals("Survey", header.surveyName)
+ assertEquals("submission", header.submissionLabel)
+ assertEquals("Loi", header.submissionName)
+ assertEquals("date", header.dateLabel)
+ assertEquals("DATE(0) TIME(0)", header.timestamp)
+ }
+
+ @Test
+ fun `table carries the submission name and the job it belongs to`() = runTest {
+ val report = FakeDataGenerator.newLoiReport(loiName = "Loi")
+
+ val table = mapper.map(report, submission)!!.document.table
+
+ assertEquals("submission", table.submissionLabel)
+ assertEquals("Loi", table.loiName)
+ assertEquals("job", table.jobLabel)
+ assertEquals("job", table.jobName)
+ }
+
+ @Test
+ fun `table falls back to the job id when the job has no name`() = runTest {
+ val unnamedJob =
+ FakeDataGenerator.newSubmission(
+ job = FakeDataGenerator.newJob(id = "job id").copy(name = null)
+ )
+
+ val table = mapper.map(FakeDataGenerator.newLoiReport(), unnamedJob)!!.document.table
+
+ assertEquals("job id", table.jobName)
+ }
+
@Test
fun `mapper returns null when submissionDetails are missing`() = runTest {
val report = FakeDataGenerator.newLoiReport(submissionDetails = null)
diff --git a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayoutTest.kt b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayoutTest.kt
index 0d8f290a69..3b5c968504 100644
--- a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayoutTest.kt
+++ b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/PageHeaderLayoutTest.kt
@@ -56,7 +56,7 @@ class PageHeaderLayoutTest {
}
@Test
- fun `compute places job column labels and values at CENTER_X`() {
+ fun `compute places submission column labels and values at CENTER_X`() {
val layout = PageHeaderLayout.compute(top = 0f, labelHeight = 10f, valueHeight = 14f)
assertEquals(PdfOffset(PageHeaderLayout.CENTER_X, 0f), layout.centerColumn.labelOffset)
@@ -67,12 +67,22 @@ class PageHeaderLayoutTest {
}
@Test
- fun `compute places timestamp at RIGHT_X with the same top as labels`() {
+ fun `compute places the date column at RIGHT_X with the same top as the other labels`() {
val layout = PageHeaderLayout.compute(top = 50f, labelHeight = 10f, valueHeight = 14f)
- assertEquals(PdfOffset(PageHeaderLayout.RIGHT_X, 50f), layout.rightTextOffset)
- assertEquals(layout.leftColumn.labelOffset.y, layout.rightTextOffset.y)
- assertEquals(layout.centerColumn.labelOffset.y, layout.rightTextOffset.y)
+ assertEquals(PdfOffset(PageHeaderLayout.RIGHT_X, 50f), layout.rightColumn.labelOffset)
+ assertEquals(layout.leftColumn.labelOffset.y, layout.rightColumn.labelOffset.y)
+ assertEquals(layout.centerColumn.labelOffset.y, layout.rightColumn.labelOffset.y)
+ }
+
+ @Test
+ fun `date value sits below its label like the other columns`() {
+ val layout = PageHeaderLayout.compute(top = 50f, labelHeight = 10f, valueHeight = 14f)
+
+ assertEquals(
+ PdfOffset(PageHeaderLayout.RIGHT_X, 50f + 10f + lineSpacing),
+ layout.rightColumn.valueOffset,
+ )
}
@Test
diff --git a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayoutTest.kt b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayoutTest.kt
index 822bb6d537..94360b5f9e 100644
--- a/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayoutTest.kt
+++ b/feature/pdf/src/commonTest/kotlin/org/groundplatform/feature/pdf/render/layout/TableLayoutTest.kt
@@ -36,29 +36,51 @@ class TableLayoutTest {
private val taskColumnWidth = TASK_COLUMN_WIDTH
@Test
- fun `label sits below a top gap at the left margin`() {
- val layout = TableLayout.getLabel(top = 100f, labelHeight = 14f)
+ fun `title sits below a top gap at the left margin`() {
+ val layout = TableLayout.getTitleBlock(top = 100f, titleHeight = 14f, subtitleHeight = 12f)
- assertEquals(PdfOffset(margin, 100f + 2 * lineSpacing), layout.labelOffset)
+ assertEquals(PdfOffset(margin, 100f + 2 * lineSpacing), layout.titleOffset)
}
@Test
- fun `label leaves a bottom gap before the first row`() {
+ fun `subtitle sits below the title at the left margin`() {
+ val titleHeight = 14f
+
+ val layout =
+ TableLayout.getTitleBlock(top = 100f, titleHeight = titleHeight, subtitleHeight = 12f)
+
+ assertEquals(
+ PdfOffset(margin, 100f + 2 * lineSpacing + titleHeight + lineSpacing),
+ layout.subtitleOffset,
+ )
+ }
+
+ @Test
+ fun `title block leaves a bottom gap before the first row`() {
val top = 100f
- val labelHeight = 14f
+ val titleHeight = 14f
+ val subtitleHeight = 12f
- val layout = TableLayout.getLabel(top = top, labelHeight = labelHeight)
+ val layout =
+ TableLayout.getTitleBlock(
+ top = top,
+ titleHeight = titleHeight,
+ subtitleHeight = subtitleHeight,
+ )
- assertEquals(top + 2 * lineSpacing + labelHeight + lineSpacing, layout.nextCursorY)
+ assertEquals(
+ top + 2 * lineSpacing + titleHeight + lineSpacing + subtitleHeight + 2 * lineSpacing,
+ layout.nextCursorY,
+ )
}
@Test
- fun `taller label pushes the first row further down`() {
- val short = TableLayout.getLabel(top = 0f, labelHeight = 10f)
- val tall = TableLayout.getLabel(top = 0f, labelHeight = 30f)
+ fun `taller title lines push the first row further down`() {
+ val short = TableLayout.getTitleBlock(top = 0f, titleHeight = 10f, subtitleHeight = 10f)
+ val tall = TableLayout.getTitleBlock(top = 0f, titleHeight = 30f, subtitleHeight = 20f)
assertTrue(short.nextCursorY < tall.nextCursorY)
- assertEquals(20f, tall.nextCursorY - short.nextCursorY)
+ assertEquals(30f, tall.nextCursorY - short.nextCursorY)
}
@Test