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