Skip to content

Commit

Permalink
refactor: refactored aim strokke code. moved all margins and stroke s…
Browse files Browse the repository at this point in the history
…izes to a constants file.
  • Loading branch information
nflsilva committed Dec 4, 2023
1 parent bb937e8 commit e4dc2af
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 68 deletions.
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ dependencies {
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.0.5"
debugImplementation "androidx.compose.ui:ui-tooling:1.0.5"


implementation "androidx.camera:camera-camera2:1.0.2"
implementation 'androidx.camera:camera-lifecycle:1.0.2'
implementation 'androidx.camera:camera-view:1.0.0-alpha31'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.clipPath
Expand All @@ -81,14 +80,24 @@ import com.outsystems.plugins.barcode.controller.helper.OSBARCMLKitHelper
import com.outsystems.plugins.barcode.controller.helper.OSBARCZXingHelper
import com.outsystems.plugins.barcode.model.OSBARCError
import com.outsystems.plugins.barcode.model.OSBARCScanParameters
import com.outsystems.plugins.barcode.view.ui.theme.ActionButtonsDistance
import com.outsystems.plugins.barcode.view.ui.theme.BarcodeScannerTheme
import com.outsystems.plugins.barcode.view.ui.theme.ButtonsBackgroundGray
import com.outsystems.plugins.barcode.view.ui.theme.ButtonsBackgroundWhite
import com.outsystems.plugins.barcode.view.ui.theme.ButtonsBorderGray
import com.outsystems.plugins.barcode.view.ui.theme.ButtonsTextGray
import com.outsystems.plugins.barcode.view.ui.theme.ButtonsTextWhite
import com.outsystems.plugins.barcode.view.ui.theme.CustomGray
import com.outsystems.plugins.barcode.view.ui.theme.NoPadding
import com.outsystems.plugins.barcode.view.ui.theme.ScanAimWhite
import com.outsystems.plugins.barcode.view.ui.theme.ScanButtonCornerRadius
import com.outsystems.plugins.barcode.view.ui.theme.ScanButtonStrokeWidth
import com.outsystems.plugins.barcode.view.ui.theme.ScanInstructionsWhite
import com.outsystems.plugins.barcode.view.ui.theme.ScannerAimCornerLength
import com.outsystems.plugins.barcode.view.ui.theme.ScannerAimRectCornerPadding
import com.outsystems.plugins.barcode.view.ui.theme.ScannerAimStrokeWidth
import com.outsystems.plugins.barcode.view.ui.theme.ScannerBackgroundBlack
import com.outsystems.plugins.barcode.view.ui.theme.ScannerBorderPadding

/**
* This class is responsible for implementing the UI of the scanning screen using Jetpack Compose.
Expand All @@ -102,6 +111,8 @@ class OSBARCScannerActivity : ComponentActivity() {
private var showDialog by mutableStateOf(false)
private var isScanning = false

private data class Point(val x: Float, val y: Float)

companion object {
private const val SCAN_SUCCESS_RESULT_CODE = -1
private const val SCAN_RESULT = "scanResult"
Expand Down Expand Up @@ -214,7 +225,7 @@ class OSBARCScannerActivity : ComponentActivity() {
Box(
modifier = Modifier
.fillMaxSize()
.safeDrawingPadding(),
.safeDrawingPadding()
) {
AndroidView(
factory = { context ->
Expand Down Expand Up @@ -258,20 +269,17 @@ class OSBARCScannerActivity : ComponentActivity() {
)

// actual UI on top of the camera stream

val configuration = LocalConfiguration.current
val screenHeight = configuration.screenHeightDp.dp
val screenWidth = configuration.screenWidthDp.dp

val borderPadding = 32.dp

val isPortrait = configuration.orientation == Configuration.ORIENTATION_PORTRAIT

if (isPortrait) {
ScanScreenUIPortrait(parameters, screenWidth, borderPadding)
ScanScreenUIPortrait(parameters, screenWidth)
}
else {
ScanScreenUILandscape(parameters, screenHeight, borderPadding)
ScanScreenUILandscape(parameters, screenHeight)
}
}
}
Expand All @@ -286,12 +294,6 @@ class OSBARCScannerActivity : ComponentActivity() {
@Composable
fun ScanScreenAim(height: Dp, horizontalPadding: Dp, verticalPadding: Dp) {

// padding from the rectangle to each corner
val rectToCornerPadding = 16.dp
// drawing edges in each corner using lines
val cornerLength = 50.dp
// width of each border
val strokeWidth = 3f

// the canvas includes the rectangle and its edges
Canvas(
Expand All @@ -307,8 +309,8 @@ class OSBARCScannerActivity : ComponentActivity() {

// rectangle size is determined by removing the padding from the border of the screen
// and the padding to the corners of the rectangle
val rectWidth = canvasWidth - (horizontalPadding.toPx() * 2) - (rectToCornerPadding.toPx() * 2)
val rectHeight = canvasHeight - (verticalPadding.toPx() * 2) - (rectToCornerPadding.toPx() * 2)
val rectWidth = canvasWidth - (horizontalPadding.toPx() * 2) - (ScannerAimRectCornerPadding.toPx() * 2)
val rectHeight = canvasHeight - (verticalPadding.toPx() * 2) - (ScannerAimRectCornerPadding.toPx() * 2)
val rectLeft = (canvasWidth - rectWidth) / 2
val rectTop = (canvasHeight - rectHeight) / 2

Expand All @@ -324,52 +326,74 @@ class OSBARCScannerActivity : ComponentActivity() {
drawRect(color= ScannerBackgroundBlack)
}

val aimTop = rectTop - rectToCornerPadding.toPx()
val aimLeft = rectLeft - rectToCornerPadding.toPx()
val aimRight = aimLeft + rectWidth + (rectToCornerPadding * 2).toPx()
val aimBottom = aimTop + rectHeight + (rectToCornerPadding * 2).toPx()
val aimLength = cornerLength.toPx()
val aimTop = rectTop - ScannerAimRectCornerPadding.toPx()
val aimLeft = rectLeft - ScannerAimRectCornerPadding.toPx()
val aimRight = aimLeft + rectWidth + (ScannerAimRectCornerPadding * 2).toPx()
val aimBottom = aimTop + rectHeight + (ScannerAimRectCornerPadding * 2).toPx()
val aimLength = ScannerAimCornerLength.toPx()

val aimPath = Path()
// top left
aimPath.moveTo(aimLeft + aimLength, aimTop)
aimPath.lineTo(aimLeft + radius, aimTop)
aimPath.quadraticBezierTo(aimLeft, aimTop, aimLeft, aimTop + radius)
aimPath.lineTo(aimLeft, aimTop + aimLength)

AddCornerToAimPath(
aimPath,
Point(aimLeft + aimLength, aimTop),
Point(aimLeft + radius, aimTop),
Point(aimLeft, aimTop),
Point(aimLeft, aimTop + radius),
Point(aimLeft, aimTop + aimLength)
)
// bottom left
aimPath.moveTo(aimLeft, aimBottom - aimLength)
aimPath.lineTo(aimLeft, aimBottom - radius)
aimPath.quadraticBezierTo(aimLeft, aimBottom, aimLeft + radius, aimBottom)
aimPath.lineTo(aimLeft + aimLength, aimBottom)

AddCornerToAimPath(
aimPath,
Point(aimLeft, aimBottom - aimLength),
Point(aimLeft, aimBottom - radius),
Point(aimLeft, aimBottom),
Point(aimLeft + radius, aimBottom),
Point(aimLeft + aimLength, aimBottom)
)
// bottom right
aimPath.moveTo(aimRight - aimLength, aimBottom)
aimPath.lineTo(aimRight - radius, aimBottom)
aimPath.quadraticBezierTo(aimRight, aimBottom, aimRight, aimBottom - radius)
aimPath.lineTo(aimRight, aimBottom - aimLength)

AddCornerToAimPath(
aimPath,
Point(aimRight - aimLength, aimBottom),
Point(aimRight - radius, aimBottom),
Point(aimRight, aimBottom),
Point(aimRight, aimBottom - radius),
Point(aimRight, aimBottom - aimLength)
)
// top right
aimPath.moveTo(aimRight, aimTop + aimLength)
aimPath.lineTo(aimRight, aimTop + radius)
aimPath.quadraticBezierTo(aimRight, aimTop, aimRight - radius, aimTop)
aimPath.lineTo(aimRight - aimLength, aimTop)

drawPath(aimPath, color = Color.White, style = Stroke(width = strokeWidth))
AddCornerToAimPath(
aimPath,
Point(aimRight, aimTop + aimLength),
Point(aimRight, aimTop + radius),
Point(aimRight, aimTop),
Point(aimRight - radius, aimTop),
Point(aimRight - aimLength, aimTop)
)
drawPath(aimPath, color = ScanAimWhite, style = Stroke(width = ScannerAimStrokeWidth))
}
)
}

private fun AddCornerToAimPath(path: Path,
startPoint: Point,
startCornerPoint: Point,
controlPoint: Point,
endCornerPoint: Point,
endPoint: Point) {
path.moveTo(startPoint.x, startPoint.y)
path.lineTo(startCornerPoint.x, startCornerPoint.y)
path.quadraticBezierTo(controlPoint.x, controlPoint.y, endCornerPoint.x, endCornerPoint.y)
path.lineTo(endPoint.x, endPoint.y)
}

/**
* Composable function, responsible rendering the main UI in portrait mode
* @param parameters the scan parameters
* @param screenHeight the screen height
* @param borderPadding the value for the border padding
*/
@Composable
fun ScanScreenUIPortrait(parameters: OSBARCScanParameters,
screenHeight:Dp,
borderPadding: Dp) {
fun ScanScreenUIPortrait(parameters: OSBARCScanParameters, screenHeight:Dp) {

Column(
modifier = Modifier
Expand All @@ -385,7 +409,7 @@ class OSBARCScannerActivity : ComponentActivity() {
) {
CloseButton(
modifier = Modifier
.padding(top = borderPadding, end = borderPadding)
.padding(top = ScannerBorderPadding, end = ScannerBorderPadding)
.align(Alignment.TopEnd)
)
}
Expand All @@ -400,11 +424,11 @@ class OSBARCScannerActivity : ComponentActivity() {
ScanInstructions(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = borderPadding),
.padding(bottom = ScannerBorderPadding),
parameters
)

ScanScreenAim(screenHeight, borderPadding, 0.dp)
ScanScreenAim(screenHeight, ScannerBorderPadding, NoPadding)
}

Box(
Expand All @@ -415,12 +439,12 @@ class OSBARCScannerActivity : ComponentActivity() {
) {
ScanActionButtons(
parameters,
0f.dp,
NoPadding,
scanModifier = Modifier
.padding(bottom = borderPadding)
.padding(bottom = ScannerBorderPadding)
.align(Alignment.BottomCenter),
torchModifier = Modifier
.padding(bottom = borderPadding, end = borderPadding)
.padding(bottom = ScannerBorderPadding, end = ScannerBorderPadding)
.align(Alignment.BottomEnd)
)
}
Expand All @@ -434,9 +458,7 @@ class OSBARCScannerActivity : ComponentActivity() {
* @param borderPadding the value for the border padding
*/
@Composable
fun ScanScreenUILandscape(parameters: OSBARCScanParameters,
screenHeight:Dp,
borderPadding: Dp) {
fun ScanScreenUILandscape(parameters: OSBARCScanParameters, screenHeight:Dp) {
Row(
modifier = Modifier
.fillMaxSize(),
Expand All @@ -460,11 +482,11 @@ class OSBARCScannerActivity : ComponentActivity() {
ScanInstructions(
modifier = Modifier
.fillMaxWidth()
.padding(top = borderPadding),
.padding(top = ScannerBorderPadding),
parameters
)

ScanScreenAim(screenHeight, 0.dp, borderPadding)
ScanScreenAim(screenHeight, NoPadding, ScannerBorderPadding)
}

Box(
Expand All @@ -476,19 +498,19 @@ class OSBARCScannerActivity : ComponentActivity() {

CloseButton(
modifier = Modifier
.padding(top = borderPadding, end = borderPadding)
.padding(top = ScannerBorderPadding, end = ScannerBorderPadding)
.align(Alignment.TopEnd)
)

Column(
modifier = Modifier
.padding(end = borderPadding)
.padding(end = ScannerBorderPadding)
.align(Alignment.CenterEnd),
verticalArrangement = Arrangement.Center
) {
ScanActionButtons(
parameters,
borderPadding,
ScannerBorderPadding,
scanModifier = Modifier
.align(Alignment.End),
torchModifier = Modifier
Expand Down Expand Up @@ -564,8 +586,8 @@ class OSBARCScannerActivity : ComponentActivity() {
colors = ButtonDefaults.buttonColors(
containerColor = backgroundColor
),
shape = RoundedCornerShape(4.dp),
border = BorderStroke(width = 1.dp, color = ButtonsBorderGray),
shape = RoundedCornerShape(ScanButtonCornerRadius),
border = BorderStroke(width = ScanButtonStrokeWidth, color = ButtonsBorderGray),
modifier = modifier
) {
Text(
Expand All @@ -592,7 +614,7 @@ class OSBARCScannerActivity : ComponentActivity() {
Text(
text = parameters.scanInstructions,
modifier = modifier,
color = Color.White,
color = ScanInstructionsWhite,
textAlign = TextAlign.Center
)
}
Expand All @@ -614,19 +636,20 @@ class OSBARCScannerActivity : ComponentActivity() {
scanModifier: Modifier,
torchModifier: Modifier) {

val actionButtonsHeight = 48.dp

val showTorch = camera.cameraInfo.hasFlashUnit()
val showScan = parameters.scanButton || true
val showScan = parameters.scanButton

val buttonsVerticalDistance = ActionButtonsDistance
val buttonSpacing = if(showTorch && showScan)
{ verticalPadding.times(0.5f) } else { verticalPadding.times(0f) }
{ buttonsVerticalDistance.times(0.5f) } else { buttonsVerticalDistance.times(0f) }

// flashlight button
if (showTorch) {
TorchButton(
torchModifier
.padding(bottom = buttonSpacing)
.size(actionButtonsHeight),
.size(buttonsVerticalDistance),
)
}

Expand All @@ -635,7 +658,7 @@ class OSBARCScannerActivity : ComponentActivity() {
ScanButton(
scanModifier
.padding(top = buttonSpacing)
.height(actionButtonsHeight),
.height(buttonsVerticalDistance),
parameters.scanText)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ val ButtonsBackgroundWhite = Color(0xFFFFFFD9)
val ButtonsTextGray = Color(0xFF4F575E)
val ButtonsTextWhite = Color(0xFFFFFFFF)

val ScanInstructionsWhite = Color(0xFFFFFFFF)
val ScanAimWhite = Color(0xFFFFFFFF)
val ScannerBackgroundBlack = Color.Black.copy(alpha = 0.6f)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.outsystems.plugins.barcode.view.ui.theme

import androidx.compose.ui.unit.dp

val NoPadding = 0f.dp
val ScannerBorderPadding = 32f.dp

val ScannerAimRectCornerPadding = 16f.dp
val ScannerAimCornerLength = 50f.dp
const val ScannerAimStrokeWidth = 3f

val ScanButtonCornerRadius = 4f.dp
val ScanButtonStrokeWidth = 1f.dp
val ActionButtonsDistance = 48f.dp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fun BarcodeScannerTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
Expand Down

0 comments on commit e4dc2af

Please sign in to comment.