Untitled
unknown
plain_text
a year ago
9.4 kB
12
Indexable
package com.teamapt.android.pos.hardware_interface.printer
import android.graphics.Bitmap
import android.graphics.Point
import androidx.annotation.DrawableRes
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import com.teamapt.android.pos.hardware_interface.printer.model.ImageFormat
import com.teamapt.android.pos.hardware_interface.printer.model.TextFormat
import com.teamapt.android.pos.hardware_interface.printer.model.elements.*
import com.teamapt.android.pos.hardware_interface.printer.model.enums.PrinterResult
import com.teamapt.android.pos.hardware_interface.printer.model.enums.PrinterStatus
import com.teamapt.android.pos.hardware_interface.printer.model.enums.TextAlignment
import com.teamapt.android.pos.hardware_interface.util.Document
import timber.log.Timber
import kotlin.math.min
const val SPACING = 1
const val COLUMN_1_MAX = 5
const val COLUMN_2_MAX = 12
interface PrinterService {
/*
* Available paper width in px. Normally close to 400px after margin deducted
*/
val paperWidth: Int
fun setupPage()
fun getStatus(): PrinterStatus
/*
* This represents the actual number of pixels taken up by a character with font size [fontSize]
*/
fun getFontSizePixels(fontSize: TextFormat.FontSize): Int
/*
* Returns the number of characters that can be printed on one line
* if each character is of [fontSize].
* The logical width is easier to work with when the text is monospaced and
* the font size is known
*/
fun getLogicalWidth(fontSize: TextFormat.FontSize): Int {
return 2 * paperWidth / getFontSizePixels(fontSize)
}
fun addPrintText(
text: String?,
startPoint: Point = Point(0, 0),
alignment: TextAlignment = TextAlignment.CENTER,
format: TextFormat = TextFormat()
)
fun addPrintImage(@DrawableRes image: Int, format: ImageFormat)
fun addPrintBitmapImage(bitmap: Bitmap, format: ImageFormat)
fun addPrintNewLine()
suspend fun print(): PrinterResult
fun clear()
fun pushPaperForwardAfterPrinting()
fun cutPaperAfterPrinting()
suspend fun printDocument(document: Document): PrinterResult {
try {
setupPage()
for (element in document) {
when (element) {
is KeyValueLine -> printKeyValueLine(element)
is SingleLabelLine -> printSingleLabelLine(element)
is SeparatorLine -> printSeparatorLine(element)
is SingleRowTextLine -> printSingleRowTextLine(element)
is NewLine -> addPrintNewLine()
is Image -> printImage(element)
is BitmapImage -> printBitmapImage(element)
}
}
return print()
} catch (e: Exception) {
Timber.e(e)
Firebase.crashlytics.log("EOD Printer Error Debug is ${e.message}")
Firebase.crashlytics.recordException(e)
return PrinterResult.ERROR_UNKNOWN
}
}
private fun printSingleLabelLine(singleLabelLine: SingleLabelLine) {
// TODO why print SingleLabelLine with KeyValueLine?
when {
singleLabelLine.alignment == TextAlignment.LEFT -> {
printKeyValueLine(
KeyValueLine(
keySegment = singleLabelLine.labelSegment,
textFormat = singleLabelLine.textFormat
)
)
}
singleLabelLine.alignment == TextAlignment.RIGHT -> {
printKeyValueLine(
KeyValueLine(
valueSegment = singleLabelLine.labelSegment,
textFormat = singleLabelLine.textFormat
)
)
}
singleLabelLine.alignment == TextAlignment.CENTER -> {
printCenterAlignedLabel(singleLabelLine)
}
}
}
private fun printKeyValueLine(keyValueLine: KeyValueLine) {
if (keyValueLine.keySegment.isEmpty() && keyValueLine.valueSegment.isEmpty()) return
val logicalWidth = getLogicalWidth(keyValueLine.textFormat.fontSize)
val bufferArray = CharArray(logicalWidth)
bufferArray.fill(' ')
val nextLine = KeyValueLine(textFormat = keyValueLine.textFormat)
val maxCountForSegment = logicalWidth / 2
if (keyValueLine.keySegment.isNotEmpty()) {
if (keyValueLine.leftSegmentCount > maxCountForSegment) {
val indexOfNextCharacter = copySegmentToCharArrayFromStart(
keyValueLine.keySegment,
bufferArray, 0, maxCountForSegment - 1
)
if (indexOfNextCharacter < keyValueLine.leftSegmentCount) {
nextLine.keySegment =
LineSegment(keyValueLine.keySegment.text.substring(indexOfNextCharacter))
}
} else {
copySegmentToCharArrayFromStart(
keyValueLine.keySegment,
bufferArray,
0,
maxCountForSegment - 1
)
}
}
if (keyValueLine.valueSegment.isNotEmpty()) {
if (keyValueLine.rightSegmentCount > maxCountForSegment) {
val indexOfNextCharacter = copySegmentToCharArrayFromStart(
keyValueLine.valueSegment,
bufferArray, maxCountForSegment, logicalWidth - 1
)
if (indexOfNextCharacter > 0) {
nextLine.valueSegment =
LineSegment(keyValueLine.valueSegment.text.substring(indexOfNextCharacter))
}
} else {
copySegmentToCharArrayFromStart(
keyValueLine.valueSegment,
bufferArray,
maxCountForSegment,
logicalWidth - 1
)
}
}
val string = String(bufferArray)
addPrintText(string, format = keyValueLine.textFormat)
if (nextLine.keySegment.isNotEmpty() || nextLine.valueSegment.isNotEmpty()) {
printKeyValueLine(nextLine)
}
}
fun printSingleRowTextLine(singleRowTextLine: SingleRowTextLine) {
val logicalWidth = getLogicalWidth(singleRowTextLine.textFormat.fontSize)
//logical width for this font size is 37
val bufferArray = CharArray(logicalWidth)
bufferArray.fill(' ')
val spacing = singleRowTextLine.columnBoundaries
singleRowTextLine.columns.forEachIndexed { index, lineSegment ->
val columnSpace = spacing.getOrNull(index) ?: IntRange(0, 0)
copySegmentToCharArrayFromStart(lineSegment, bufferArray, columnSpace.first, columnSpace.last)
}
val string = String(bufferArray)
addPrintText(string, format = singleRowTextLine.textFormat)
}
private fun printSeparatorLine(separatorLine: SeparatorLine) {
val logicalWidth = getLogicalWidth(separatorLine.textFormat.fontSize)
val bufferArray = CharArray(logicalWidth)
bufferArray.fill(separatorLine.separator)
val text = String(bufferArray)
addPrintText(text)
}
private fun printCenterAlignedLabel(singleLabelLine: SingleLabelLine) {
if (singleLabelLine.labelSegment.isEmpty()) return
val logicalWidth = getLogicalWidth(singleLabelLine.textFormat.fontSize)
val bufferArray = CharArray(logicalWidth)
bufferArray.fill(' ')
val nextLine = SingleLabelLine(
textFormat = singleLabelLine.textFormat,
alignment = singleLabelLine.alignment
)
val maxCountForSegment = logicalWidth - 4 // Minimum padding is 2 spaces.
if (singleLabelLine.count > maxCountForSegment) {
val indexOfNextCharacter = copySegmentToCharArrayFromStart(
singleLabelLine.labelSegment,
bufferArray, 2, logicalWidth - 3
)
nextLine.labelSegment =
LineSegment(singleLabelLine.labelSegment.text.substring(indexOfNextCharacter))
} else {
val startIndex = (logicalWidth - singleLabelLine.count) / 2
copySegmentToCharArrayFromStart(
singleLabelLine.labelSegment, bufferArray, startIndex, startIndex
+ singleLabelLine.count
)
}
val string = String(bufferArray)
addPrintText(string, format = singleLabelLine.textFormat)
if (nextLine.labelSegment.isNotEmpty()) {
printSingleLabelLine(nextLine)
}
}
private fun copySegmentToCharArrayFromStart(
lineSegment: LineSegment, bufferArray: CharArray,
startIndex: Int, endIndex: Int
): Int {
var i = 0
var k = startIndex
while (i < min(lineSegment.text.length, endIndex) && k < bufferArray.size) {
bufferArray[k++] = lineSegment.text[i++]
}
return i
}
private fun printImage(image: Image) {
addPrintImage(image.resource, image.format)
}
private fun printBitmapImage(image: BitmapImage) {
addPrintBitmapImage(image.bitmap, image.format)
}
}
Editor is loading...
Leave a Comment