Skip to content

Commit

Permalink
Merge pull request #20 from OutSystems/feat/RMET-2987/add-zoom
Browse files Browse the repository at this point in the history
RMET-2987 OSBarcodeLib-Android - Add zoom options
  • Loading branch information
alexgerardojacinto authored Mar 27, 2024
2 parents 4132c64 + 0f4e818 commit 8d77f6d
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 62 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ The changes documented here do not include those from the original repository.

## [Unreleased]

### 26-03-2024
- Add zoom options (https://outsystemsrd.atlassian.net/browse/RMET-2987).

### 22-02-2024
- Update `github_actions.yml` file steps versions (https://outsystemsrd.atlassian.net/browse/RMET-2568).

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.outsystems</groupId>
<artifactId>osbarcode-android</artifactId>
<version>1.0.0</version>
<version>1.0.0.5</version>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,23 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
Expand All @@ -65,6 +70,7 @@ 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 Down Expand Up @@ -92,8 +98,9 @@ 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.ButtonsTextOrange
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.CloseButtonBackground
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
Expand All @@ -105,8 +112,12 @@ 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
import com.outsystems.plugins.barcode.view.ui.theme.TextToRectPadding
import com.outsystems.plugins.barcode.view.ui.theme.ZoomButtonBackground
import com.outsystems.plugins.barcode.view.ui.theme.ZoomButtonBackgroundSelected
import com.outsystems.plugins.barcode.view.ui.theme.ZoomButtonSize
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.roundToInt

/**
* This class is responsible for implementing the UI of the scanning screen using Jetpack Compose.
Expand Down Expand Up @@ -516,16 +527,36 @@ class OSBARCScannerActivity : ComponentActivity() {
.background(ScannerBackgroundBlack)
.weight(1f, fill = true),
) {
ScanActionButtons(
parameters,
NoPadding,
scanModifier = Modifier
val showTorch = camera.cameraInfo.hasFlashUnit()
val showScan = parameters.scanButton

Column(
modifier = Modifier
.padding(bottom = ScannerBorderPadding)
.align(Alignment.BottomCenter),
torchModifier = Modifier
.padding(bottom = ScannerBorderPadding, end = ScannerBorderPadding)
.align(Alignment.BottomEnd)
)
horizontalAlignment = Alignment.CenterHorizontally
) {

ZoomButtons()

// scan button to turn on scanning when used
if (showScan) {
Spacer(modifier = Modifier.height(16.dp))
ScanButton(
modifier = Modifier
.height(ActionButtonsDistance),
parameters.scanText)
}
}

// flashlight button
if (showTorch) {
TorchButton(
modifier = Modifier
.padding(bottom = ScannerBorderPadding, end = ScannerBorderPadding)
.align(Alignment.BottomEnd)
)
}
}
}
}
Expand Down Expand Up @@ -575,7 +606,10 @@ class OSBARCScannerActivity : ComponentActivity() {
ScanInstructions(
modifier = Modifier
.fillMaxWidth()
.padding(top = borderPadding, bottom = if (isPhone) NoPadding else textToRectPadding),
.padding(
top = borderPadding,
bottom = if (isPhone) NoPadding else textToRectPadding
),
parameters
)

Expand Down Expand Up @@ -607,20 +641,33 @@ class OSBARCScannerActivity : ComponentActivity() {
modifier = Modifier
.padding(end = ScannerBorderPadding)
.align(Alignment.CenterEnd),
verticalArrangement = Arrangement.Center
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.End
) {
ScanActionButtons(
parameters,
ScannerBorderPadding,
scanModifier = Modifier
.align(Alignment.End),
torchModifier = Modifier
.align(Alignment.End),
)
}
val showTorch = camera.cameraInfo.hasFlashUnit()
val showScan = parameters.scanButton

// flashlight button
if (showTorch) {
TorchButton(
modifier = Modifier
.align(Alignment.End)
)
Spacer(modifier = Modifier.height(16.dp))
}

}
ZoomButtons()

// scan button to turn on scanning when used
if (showScan) {
Spacer(modifier = Modifier.height(16.dp))
ScanButton(
modifier = Modifier
.height(ActionButtonsDistance),
parameters.scanText)
}
}
}
}
}

Expand All @@ -633,12 +680,14 @@ class OSBARCScannerActivity : ComponentActivity() {
Icon(
painter = painterResource(id = R.drawable.close),
contentDescription = null,
tint = CustomGray,
tint = Color.White,
modifier = modifier
.background(color = CloseButtonBackground, shape = CircleShape)
.clickable {
setResult(OSBARCError.SCAN_CANCELLED_ERROR.code)
finish()
}
.padding(12.dp)
)
}

Expand Down Expand Up @@ -723,45 +772,115 @@ class OSBARCScannerActivity : ComponentActivity() {
}

/**
* Composable function, responsible for building the action buttons
* on the UI.
* This component will only be rendered if scan parameters instructs so.
* @param parameters the scan parameters
* @param verticalPadding the vertical spacing between buttons
* @param scanModifier the custom modifier for the scan button
* @param torchModifier the custom modifier for the torch button
* Composable function, responsible for building the zoom buttons on the UI.
*/
@Composable
fun ScanActionButtons(parameters: OSBARCScanParameters,
verticalPadding: Dp,
scanModifier: Modifier,
torchModifier: Modifier) {

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

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

// flashlight button
if (showTorch) {
TorchButton(
torchModifier
.padding(bottom = buttonSpacing)
.size(ActionButtonsDistance),
)
fun ZoomButtons() {
val minZoomRatio = camera.cameraInfo.zoomState.value?.minZoomRatio ?: 1f
val roundedRatio = (minZoomRatio * 10).roundToInt() / 10f
val maxZoomRatio = camera.cameraInfo.zoomState.value?.maxZoomRatio ?: 1f
var selectedButton by remember { mutableStateOf(2) }

Row(
modifier = Modifier
.background(ButtonsBackgroundGray, CircleShape)
.wrapContentWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
// we only show the button with zoom below zero if that zoom value is possible
if (minZoomRatio < 1f) {
ZoomButton(
modifier = Modifier
.padding(start = 6.dp, end = 8.dp),
selectedButton = selectedButton,
buttonToCompare = 1,
"$roundedRatio${getZoomButtonSuffix(selectedButton, 1)}",
onClick = {
selectedButton = 1
camera.cameraControl.setZoomRatio(minZoomRatio)
}
)
}

// we only want to show 1x button if there are more buttons
// if 1x is the only button, might as well not show it
if (minZoomRatio < 1f || maxZoomRatio >= 2f) {
ZoomButton(
modifier = Modifier
.padding(
start = if (minZoomRatio < 1) 0.dp else 6.dp,
end = if (maxZoomRatio >= 2) 8.dp else 6.dp
),
selectedButton = selectedButton,
buttonToCompare = 2,
"1${getZoomButtonSuffix(selectedButton, 2)}",
onClick = {
selectedButton = 2
camera.cameraControl.setZoomRatio(1f)
}
)
}

// we only show 2x button if that zoom is available
if (maxZoomRatio >= 2f) {
ZoomButton(
modifier = Modifier
.padding(end = 6.dp),
selectedButton = selectedButton,
buttonToCompare = 3,
"2${getZoomButtonSuffix(selectedButton, 3)}",
onClick = {
selectedButton = 3
camera.cameraControl.setZoomRatio(2f)
}
)
}
}
}

// scan button to turn on scanning when used
if (showScan) {
ScanButton(
scanModifier
.padding(top = buttonSpacing)
.height(ActionButtonsDistance),
parameters.scanText)
/**
* Composable function, responsible for building single zoom button on the UI.
* @param modifier - modifier to be used in button
* @param selectedButton - information about the selected button (1, 2 or 3)
* @param buttonToCompare - value to compare with selectedButton
* @param buttonText - string to be used in Text composable
* @param onClick - closure to be called when clicking the button
*/
@Composable
fun ZoomButton(
modifier: Modifier = Modifier,
selectedButton: Int,
buttonToCompare: Int,
buttonText: String,
onClick: () -> Unit
) {
OutlinedButton(
onClick = onClick,
modifier = modifier
.padding(top = 4.dp, bottom = 4.dp)
.size(ZoomButtonSize),
shape = CircleShape,
colors = ButtonDefaults.buttonColors(
containerColor = if (selectedButton == buttonToCompare) ZoomButtonBackgroundSelected else ZoomButtonBackground
),
contentPadding = PaddingValues(NoPadding), // so that text shows
) {
Text(
text = buttonText,
color = if (selectedButton == buttonToCompare) ButtonsTextOrange else ButtonsTextWhite,
textAlign = TextAlign.Center,
)
}
}

/**
* Helper function to determine suffix for zoom buttons
*/
private fun getZoomButtonSuffix(selectedButton: Int, buttonToCompare: Int): String {
return if (selectedButton == buttonToCompare) "x" else ""
}

private fun hasCameraPermission(context: Context): Boolean {
return ContextCompat.checkSelfPermission(
context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ val ButtonsBorderGray = Color(0xFF4F575E)
val ButtonsBackgroundWhite = Color(0xFFFFFFD9)
val ButtonsTextGray = Color(0xFF4F575E)
val ButtonsTextWhite = Color(0xFFFFFFFF)
val ButtonsTextOrange = Color(0xFFF59F00)

val ScanInstructionsWhite = Color(0xFFFFFFFF)
val ScanAimWhite = Color(0xFFFFFFFF)
val ScannerBackgroundBlack = Color.Black.copy(alpha = 0.6f)
val ScannerBackgroundBlack = Color.Black.copy(alpha = 0.6f)
val ZoomButtonBackground = Color.Black.copy(alpha = 0.2f)
val ZoomButtonBackgroundSelected = Color.Black.copy(alpha = 0.5f)
val CloseButtonBackground = Color.Black.copy(alpha = 0.90f)
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ val ActionButtonsDistance = 48f.dp

const val SizeRatioWidth = 0.6
const val SizeRatioHeight = 0.5

val ZoomButtonSize = 35f.dp
13 changes: 7 additions & 6 deletions src/main/res/drawable/close.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
android:width="14dp"
android:height="14dp"
android:viewportWidth="14"
android:viewportHeight="14">
<path
android:pathData="M14.586,16L5.293,25.293L6.707,26.707L16,17.414L25.293,26.707L26.707,25.293L17.414,16L26.707,6.707L25.293,5.293L16,14.586L6.707,5.293L5.293,6.707L14.586,16Z"
android:fillColor="#B3BAC4"/>
android:pathData="M13.53,1.53C13.823,1.237 13.823,0.763 13.53,0.47C13.237,0.177 12.763,0.177 12.47,0.47L7,5.939L1.53,0.47C1.237,0.177 0.763,0.177 0.47,0.47C0.177,0.763 0.177,1.237 0.47,1.53L5.939,7L0.47,12.47C0.177,12.763 0.177,13.237 0.47,13.53C0.763,13.823 1.237,13.823 1.53,13.53L7,8.061L12.47,13.53C12.763,13.823 13.237,13.823 13.53,13.53C13.823,13.237 13.823,12.763 13.53,12.47L8.061,7L13.53,1.53Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

0 comments on commit 8d77f6d

Please sign in to comment.