Added scanner for qr codes and updated logo

This commit is contained in:
Mariano Riefolo 2024-02-26 16:58:41 +01:00
parent 2bc30fd106
commit 77741103b0
10 changed files with 199 additions and 10 deletions

View File

@ -15,7 +15,7 @@
</deviceKey> </deviceKey>
</Target> </Target>
</targetSelectedWithDropDown> </targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-02-24T17:02:56.140502018Z" /> <timeTargetWasSelectedWithDropDown value="2024-02-26T15:23:42.854086595Z" />
</State> </State>
</entry> </entry>
</value> </value>

View File

@ -72,4 +72,10 @@ dependencies {
ksp("io.github.raamcosta.compose-destinations:ksp:1.0.2-beta") ksp("io.github.raamcosta.compose-destinations:ksp:1.0.2-beta")
implementation("androidx.compose.material:material-icons-extended:1.6.2") implementation("androidx.compose.material:material-icons-extended:1.6.2")
implementation("com.google.accompanist:accompanist-permissions:0.34.0")
implementation("androidx.camera:camera-camera2:1.3.1")
implementation("androidx.camera:camera-lifecycle:1.3.1")
implementation("androidx.camera:camera-view:1.3.1")
implementation("com.google.mlkit:barcode-scanning:17.2.0")
} }

View File

@ -2,6 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.CAMERA"/>
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
@ -15,7 +19,6 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.FlowSchool"> android:theme="@style/Theme.FlowSchool">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@ -0,0 +1,56 @@
package it.edu.cassandroferminervi.flowschool.screens
import android.util.Log
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import it.edu.cassandroferminervi.flowschool.util.QrAnalyzer
@Composable
fun CameraScreen() {
val localContext = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val cameraProviderFuture = remember {
ProcessCameraProvider.getInstance(localContext)
}
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
val previewView = PreviewView(context)
val preview = Preview.Builder().build()
val selector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
preview.setSurfaceProvider(previewView.surfaceProvider)
val imageAnalysis = ImageAnalysis.Builder().build()
imageAnalysis.setAnalyzer(
ContextCompat.getMainExecutor(context),
QrAnalyzer(context)
)
runCatching {
cameraProviderFuture.get().bindToLifecycle(
lifecycleOwner,
selector,
preview,
imageAnalysis
)
}.onFailure {
Log.e("CAMERA", "Camera bind error ${it.localizedMessage}", it)
}
previewView
}
)
}

View File

@ -0,0 +1,41 @@
package it.edu.cassandroferminervi.flowschool.screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.PermissionScreenDestination
import com.ramcosta.composedestinations.SearchingScreenDestination
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@Destination
@Composable
fun HomeScreen(navigator: DestinationsNavigator) {
Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 50.dp)
) {
Button(onClick = {
navigator.navigate(PermissionScreenDestination)
}, modifier = Modifier.align(Alignment.CenterHorizontally)) {
Text("Scannerizza codice QR")
}
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = {
navigator.navigate(SearchingScreenDestination)
}, modifier = Modifier.align(Alignment.CenterHorizontally)) {
Text("Cerca professore")
}
}
}

View File

@ -1,4 +1,4 @@
package it.edu.cassandroferminervi.flowschool package it.edu.cassandroferminervi.flowschool.screens
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.Visibility
@ -25,6 +26,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
@ -33,6 +35,7 @@ import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.HomeScreenDestination import com.ramcosta.composedestinations.HomeScreenDestination
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import it.edu.cassandroferminervi.flowschool.R
@Destination(start = true) @Destination(start = true)
@Composable @Composable
@ -50,8 +53,10 @@ fun LoginScreen(navigator: DestinationsNavigator) {
Image( Image(
painterResource(id = R.drawable.logo), painterResource(id = R.drawable.logo),
contentDescription = "Logo", contentDescription = "Logo",
//alignment = Alignment.Center, Modifier
Modifier.size(192.dp).align(Alignment.CenterHorizontally) .size(192.dp)
.align(Alignment.CenterHorizontally)
.clip(CircleShape)
) )
Spacer(modifier = Modifier.height(64.dp)) Spacer(modifier = Modifier.height(64.dp))
TextField( TextField(

View File

@ -0,0 +1,39 @@
package it.edu.cassandroferminervi.flowschool.screens
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale
import com.ramcosta.composedestinations.annotation.Destination
@OptIn(ExperimentalPermissionsApi::class)
@Destination
@Composable
fun PermissionScreen() {
val cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA)
if (cameraPermissionState.status.isGranted) {
CameraScreen()
} else {
Box (
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
) {
if (cameraPermissionState.status.shouldShowRationale) {
Text("Attiva il permesso per la fotocamera dalle impostazioni")
} else {
SideEffect {
cameraPermissionState.run { launchPermissionRequest() }
}
Text("Permessi disattivati per la fotocamera")
}
}
}
}

View File

@ -1,4 +1,4 @@
package it.edu.cassandroferminervi.flowschool package it.edu.cassandroferminervi.flowschool.screens
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -7,15 +7,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@Destination @Destination
@Composable @Composable
fun HomeScreen(navigator: DestinationsNavigator) { fun SearchingScreen() {
Box ( Box (
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
Text("Home page") Text("Searching screen")
} }
} }

View File

@ -0,0 +1,40 @@
package it.edu.cassandroferminervi.flowschool.util
import android.annotation.SuppressLint
import android.content.Context
import android.widget.Toast
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
class QrAnalyzer(private val context: Context) : ImageAnalysis.Analyzer {
private val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(Barcode.FORMAT_QR_CODE)
.build()
private val scanner = BarcodeScanning.getClient(options)
@SuppressLint("UnsafeOptInUsageError")
override fun analyze(imageProxy: ImageProxy) {
imageProxy.image
?.let { image ->
scanner.process(
InputImage.fromMediaImage(
image, imageProxy.imageInfo.rotationDegrees
)
).addOnSuccessListener { barcode ->
barcode?.takeIf { it.isNotEmpty() }
?.mapNotNull { it.rawValue }
?.joinToString(",")
?.let { Toast.makeText(context, it, Toast.LENGTH_SHORT).show() }
}.addOnCompleteListener {
imageProxy.close()
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 KiB

After

Width:  |  Height:  |  Size: 56 KiB