Updated the pdf generator, and improved pdf design

This commit is contained in:
sathwikcs
2025-01-17 16:35:52 +05:30
parent eba4783a88
commit 3bb2b58ce1

View File

@@ -1,19 +1,23 @@
package `in`.sminnovations.smiadmin.ui
import android.content.Context
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Shader
import android.graphics.Typeface
import android.graphics.pdf.PdfDocument
import android.os.Environment
import java.io.File
import java.io.FileOutputStream
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.Color
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import `in`.sminnovations.smiadmin.data.Employee
import kotlinx.coroutines.tasks.await
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.*
import java.util.Calendar
import java.util.Locale
class PDFGenerator(
private val context: Context,
@@ -23,16 +27,22 @@ class PDFGenerator(
private lateinit var currentPage: PdfDocument.Page
private lateinit var canvas: android.graphics.Canvas
private var currentY: Float = 0f
private val startX = 40f
private val pageHeight = 842f // A4 height
private val pageWidth = 595f // A4 width
private var pageNumber = 1
// Define colors
private val primaryColor = Color.rgb(41, 128, 185) // Blue
private val secondaryColor = Color.rgb(44, 62, 80) // Dark Blue
private val borderColor = Color.rgb(189, 195, 199) // Light Gray
private val backgroundColor = Color.rgb(236, 240, 241) // Very Light Gray
// Constants for page layout
private val pageWidth = 595f // A4 width
private val pageHeight = 842f // A4 height
private val margin = 40f
private val contentWidth = pageWidth - (2 * margin)
// Professional color scheme
private val primaryColor = Color.rgb(41, 128, 185) // Professional blue
private val secondaryColor = Color.rgb(44, 62, 80) // Dark blue
private val accentColor = Color.rgb(230, 126, 34) // Orange for highlights
private val backgroundColor = Color.rgb(236, 240, 241) // Light gray
private val borderColor = Color.rgb(189, 195, 199) // Medium gray
private val textColor = Color.rgb(52, 73, 94) // Dark gray for text
private var pageNumber = 1
suspend fun generateAttendanceReport(
employees: List<Employee>,
@@ -42,35 +52,43 @@ class PDFGenerator(
document = PdfDocument()
createNewPage()
// Setup paints
val headerPaint = Paint().apply {
textSize = 28f
textAlign = Paint.Align.CENTER
typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
// Create paint objects
val titlePaint = Paint().apply {
textSize = 32f
typeface = Typeface.create("sans-serif-light", Typeface.BOLD)
color = primaryColor
textAlign = Paint.Align.CENTER
}
val subHeaderPaint = Paint().apply {
textSize = 20f
textAlign = Paint.Align.CENTER
val subtitlePaint = Paint().apply {
textSize = 24f
typeface = Typeface.create("sans-serif-light", Typeface.NORMAL)
color = secondaryColor
textAlign = Paint.Align.CENTER
}
val tableHeaderPaint = Paint().apply {
textSize = 14f
textAlign = Paint.Align.LEFT
typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
typeface = Typeface.create("sans-serif-medium", Typeface.BOLD)
color = Color.WHITE
}
val tablePaint = Paint().apply {
val regularPaint = Paint().apply {
textSize = 12f
textAlign = Paint.Align.LEFT
color = secondaryColor
typeface = Typeface.create("sans-serif", Typeface.NORMAL)
color = textColor
}
// Draw headers and table
drawPageHeaders(headerPaint, subHeaderPaint, selectedYear, selectedMonth)
val highlightPaint = Paint().apply {
textSize = 12f
typeface = Typeface.create("sans-serif-medium", Typeface.BOLD)
color = accentColor
}
// Draw report header
drawReportHeader(selectedYear, selectedMonth, titlePaint, subtitlePaint)
// Draw table headers
drawTableHeaders(tableHeaderPaint)
// Process each employee
@@ -78,7 +96,6 @@ class PDFGenerator(
if (currentY > pageHeight - 100) {
finishCurrentPage()
createNewPage()
drawPageHeaders(headerPaint, subHeaderPaint, selectedYear, selectedMonth)
drawTableHeaders(tableHeaderPaint)
}
@@ -98,58 +115,166 @@ class PDFGenerator(
}
.sorted()
// Draw row background
val rowPaint = Paint().apply {
color = if ((employees.indexOf(employee) % 2) == 0) {
backgroundColor
} else {
Color.WHITE
}
}
val rowHeight = 60f
canvas.drawRect(startX, currentY, pageWidth - startX, currentY + rowHeight, rowPaint)
// Draw employee details
val nameY = currentY + 25f
canvas.drawText(employee.Name, startX + 10f, nameY, tablePaint)
canvas.drawText(
"${presentDates.size} days",
startX + 190f,
nameY,
tablePaint
)
// Format dates in groups of 5
val datesText = presentDates.chunked(5).joinToString("\n") { chunk ->
chunk.joinToString(", ") { day -> String.format("%02d", day) }
}
// Draw dates in multiple lines if needed
var dateY = nameY
datesText.split("\n").forEach { line ->
canvas.drawText(line, startX + 290f, dateY, tablePaint)
dateY += 15f
}
// Draw row borders
val borderPaint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 0.5f
color = borderColor
}
canvas.drawLine(
startX, currentY + rowHeight,
pageWidth - startX, currentY + rowHeight,
borderPaint
)
currentY += rowHeight
drawEmployeeRow(employee, presentDates, regularPaint, highlightPaint)
}
// Add footer with page numbers
drawFooter(regularPaint)
// Finish and save document
finishCurrentPage()
return saveDocument(selectedYear, selectedMonth)
}
private fun drawReportHeader(
selectedYear: Int,
selectedMonth: Int,
titlePaint: Paint,
subtitlePaint: Paint
) {
// Draw decorative header background
val headerPath = Path().apply {
moveTo(0f, 0f)
lineTo(pageWidth, 0f)
lineTo(pageWidth, 120f)
quadTo(pageWidth/2, 140f, 0f, 120f)
close()
}
canvas.drawPath(headerPath, Paint().apply {
color = primaryColor
alpha = 20
})
// Draw company name
canvas.drawText(companyName, pageWidth/2, 70f, titlePaint)
// Draw report title
val monthName = SimpleDateFormat("MMMM", Locale.getDefault())
.format(Calendar.getInstance().apply {
set(Calendar.MONTH, selectedMonth - 1)
}.time)
canvas.drawText(
"Monthly Attendance Summary",
pageWidth/2,
105f,
subtitlePaint
)
canvas.drawText(
"$monthName $selectedYear",
pageWidth/2,
135f,
subtitlePaint
)
currentY = 180f
}
private fun drawTableHeaders(headerPaint: Paint) {
val headerHeight = 45f
// Create gradient for header background
val gradient = LinearGradient(
margin, currentY,
margin, currentY + headerHeight,
primaryColor,
secondaryColor,
Shader.TileMode.CLAMP
)
// Draw header background with gradient
canvas.drawRoundRect(
margin, currentY,
pageWidth - margin,
currentY + headerHeight,
8f, 8f,
Paint().apply { shader = gradient }
)
// Draw column headers
var xPos = margin + 15f
canvas.drawText("Employee Name", xPos, currentY + 30f, headerPaint)
xPos += 180f
canvas.drawText("Days Present", xPos, currentY + 30f, headerPaint)
xPos += 100f
canvas.drawText("Attendance Dates", xPos, currentY + 30f, headerPaint)
currentY += headerHeight + 5f
}
private fun drawEmployeeRow(
employee: Employee,
presentDates: List<Int>,
regularPaint: Paint,
highlightPaint: Paint
) {
val rowHeight = 60f
// Draw row background
canvas.drawRoundRect(
margin, currentY,
pageWidth - margin,
currentY + rowHeight,
4f, 4f,
Paint().apply {
color = backgroundColor
}
)
// Draw employee name
canvas.drawText(
employee.Name,
margin + 15f,
currentY + 35f,
regularPaint
)
// Draw days present
canvas.drawText(
"${presentDates.size} days",
margin + 195f,
currentY + 35f,
highlightPaint
)
// Draw attendance dates
val datesText = presentDates.chunked(5)
.joinToString("\n") { chunk ->
chunk.joinToString(", ") {
String.format("%02d", it)
}
}
var dateY = currentY + 25f
datesText.split("\n").forEach { line ->
canvas.drawText(
line,
margin + 295f,
dateY,
regularPaint
)
dateY += 15f
}
currentY += rowHeight + 5f
}
private fun drawFooter(paint: Paint) {
paint.textAlign = Paint.Align.CENTER
paint.textSize = 10f
canvas.drawText(
"Page $pageNumber",
pageWidth/2,
pageHeight - margin/2,
paint
)
}
private fun saveDocument(selectedYear: Int, selectedMonth: Int): File {
val fileName = "Attendance_Summary_${selectedYear}_${selectedMonth}.pdf"
val file = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
@@ -165,58 +290,18 @@ class PDFGenerator(
}
private fun createNewPage() {
val pageInfo = PdfDocument.PageInfo.Builder(pageWidth.toInt(), pageHeight.toInt(), pageNumber++).create()
val pageInfo = PdfDocument.PageInfo.Builder(
pageWidth.toInt(),
pageHeight.toInt(),
pageNumber++
).create()
currentPage = document.startPage(pageInfo)
canvas = currentPage.canvas
currentY = 120f
currentY = margin
}
private fun finishCurrentPage() {
document.finishPage(currentPage)
}
private fun drawPageHeaders(
headerPaint: Paint,
subHeaderPaint: Paint,
selectedYear: Int,
selectedMonth: Int
) {
// Draw company logo background
val logoBgPaint = Paint().apply {
color = primaryColor
alpha = 30
}
canvas.drawCircle(pageWidth / 2f, 45f, 100f, logoBgPaint)
// Draw company name
canvas.drawText(companyName, pageWidth / 2f, 60f, headerPaint)
// Draw report title
val monthName = SimpleDateFormat("MMMM", Locale.getDefault())
.format(Calendar.getInstance().apply {
set(Calendar.MONTH, selectedMonth - 1)
}.time)
val reportTitle = "Monthly Attendance Summary - $monthName $selectedYear"
canvas.drawText(reportTitle, pageWidth / 2f, 95f, subHeaderPaint)
currentY = 140f
}
private fun drawTableHeaders(headerPaint: Paint) {
// Draw header background
val headerBgPaint = Paint().apply {
color = primaryColor
}
val headerHeight = 40f
canvas.drawRect(startX, currentY, pageWidth - startX, currentY + headerHeight, headerBgPaint)
// Draw column headers
val textY = currentY + 25f
canvas.drawText("Employee Name", startX + 10f, textY, headerPaint)
canvas.drawText("Present Days", startX + 190f, textY, headerPaint)
canvas.drawText("Dates Present", startX + 290f, textY, headerPaint)
currentY += headerHeight
}
}