fully working
This commit is contained in:
parent
b51834635a
commit
532a613179
9 changed files with 142 additions and 19 deletions
32
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
32
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -43,7 +43,7 @@ android {
|
||||||
buildConfig = true
|
buildConfig = true
|
||||||
}
|
}
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion = "1.2.0"
|
kotlinCompilerExtensionVersion = "1.4.3"
|
||||||
}
|
}
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
resources {
|
resources {
|
||||||
|
|
41
app/src/main/java/com/henryhiles/qscan/LabeledCheckbox.kt
Normal file
41
app/src/main/java/com/henryhiles/qscan/LabeledCheckbox.kt
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package com.henryhiles.qscan
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.Checkbox
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LabelledCheckBox(
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChange: ((Boolean) -> Unit),
|
||||||
|
label: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = modifier
|
||||||
|
.clickable(
|
||||||
|
indication = null,
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
onClick = { onCheckedChange(!checked) }
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Checkbox(
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = null
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Text(
|
||||||
|
text = label,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,13 @@
|
||||||
package com.henryhiles.qscan
|
package com.henryhiles.qscan
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Size
|
import android.util.Size
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
@ -20,6 +23,7 @@ import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
@ -47,13 +51,26 @@ class MainActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@ExperimentalMaterial3Api
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Screen() {
|
fun Screen() {
|
||||||
var code by remember { mutableStateOf("") }
|
var code by remember { mutableStateOf("") }
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||||
|
val activity = lifeCycleOwner as Activity
|
||||||
|
val sharedPref = activity.getPreferences(Context.MODE_PRIVATE)
|
||||||
|
var doNotAsk by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
sharedPref.getBoolean(
|
||||||
|
R.string.should_auto_open_key.toString(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
var prompted by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
val cameraProviderFuture = remember {
|
val cameraProviderFuture = remember {
|
||||||
ProcessCameraProvider.getInstance(context)
|
ProcessCameraProvider.getInstance(context)
|
||||||
}
|
}
|
||||||
|
@ -67,12 +84,31 @@ fun Screen() {
|
||||||
}
|
}
|
||||||
val launcher = rememberLauncherForActivityResult(
|
val launcher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.RequestPermission(),
|
contract = ActivityResultContracts.RequestPermission(),
|
||||||
onResult = { granted -> hasCamPermission = granted }
|
onResult = { granted ->
|
||||||
|
hasCamPermission = granted
|
||||||
|
prompted = true
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(key1 = true) {
|
LaunchedEffect(key1 = true) {
|
||||||
launcher.launch(Manifest.permission.CAMERA)
|
launcher.launch(Manifest.permission.CAMERA)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = code) {
|
||||||
|
Toast.makeText(context, "Test $doNotAsk $code", Toast.LENGTH_LONG).show()
|
||||||
|
if (doNotAsk && URLUtil.isValidUrl(code)) {
|
||||||
|
uriHandler.openUri(code)
|
||||||
|
code = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = doNotAsk) {
|
||||||
|
with(sharedPref.edit()) {
|
||||||
|
putBoolean(R.string.should_auto_open_key.toString(), doNotAsk)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
if (hasCamPermission) {
|
if (hasCamPermission) {
|
||||||
AndroidView(
|
AndroidView(
|
||||||
|
@ -102,15 +138,10 @@ fun Screen() {
|
||||||
}, modifier = Modifier
|
}, modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
)
|
)
|
||||||
if (code != "") {
|
if (code != "" && !doNotAsk) {
|
||||||
val uriHandler = LocalUriHandler.current
|
|
||||||
val isURL = URLUtil.isValidUrl(code)
|
val isURL = URLUtil.isValidUrl(code)
|
||||||
// val sharedPref =
|
|
||||||
// activity.getPreferences(Context.MODE_PRIVATE)
|
var tempDoNotAsk by remember { mutableStateOf(false) }
|
||||||
// with(sharedPref.edit()) {
|
|
||||||
// putBoolean("", true)
|
|
||||||
// apply()
|
|
||||||
// }
|
|
||||||
|
|
||||||
AlertDialog(onDismissRequest = { code = "" }) {
|
AlertDialog(onDismissRequest = { code = "" }) {
|
||||||
Surface(
|
Surface(
|
||||||
|
@ -130,6 +161,14 @@ fun Screen() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
LabelledCheckBox(
|
||||||
|
checked = tempDoNotAsk,
|
||||||
|
onCheckedChange = { tempDoNotAsk = it },
|
||||||
|
label = "Don't ask again"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.End
|
horizontalArrangement = Arrangement.End
|
||||||
|
@ -141,7 +180,11 @@ fun Screen() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (isURL)
|
if (isURL)
|
||||||
TextButton(onClick = { uriHandler.openUri(code) }) {
|
TextButton(onClick = {
|
||||||
|
uriHandler.openUri(code)
|
||||||
|
doNotAsk = tempDoNotAsk
|
||||||
|
code = ""
|
||||||
|
}) {
|
||||||
Text(
|
Text(
|
||||||
text = "Open URL",
|
text = "Open URL",
|
||||||
style = MaterialTheme.typography.labelLarge
|
style = MaterialTheme.typography.labelLarge
|
||||||
|
@ -152,7 +195,7 @@ fun Screen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else AlertDialog(onDismissRequest = {}) {
|
} else if (prompted) AlertDialog(onDismissRequest = {}) {
|
||||||
Surface(
|
Surface(
|
||||||
shape = MaterialTheme.shapes.large
|
shape = MaterialTheme.shapes.large
|
||||||
) {
|
) {
|
||||||
|
@ -174,7 +217,9 @@ fun Screen() {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.End
|
horizontalArrangement = Arrangement.End
|
||||||
) {
|
) {
|
||||||
TextButton(onClick = { }) {
|
TextButton(onClick = {
|
||||||
|
launcher.launch(Manifest.permission.CAMERA)
|
||||||
|
}) {
|
||||||
Text(
|
Text(
|
||||||
text = "Grant Permission",
|
text = "Grant Permission",
|
||||||
style = MaterialTheme.typography.labelLarge
|
style = MaterialTheme.typography.labelLarge
|
||||||
|
|
|
@ -37,7 +37,7 @@ class QrCodeAnalyzer(private val onQrCodeScanned: (String) -> Unit) : ImageAnaly
|
||||||
}.decode(binaryBmp)
|
}.decode(binaryBmp)
|
||||||
onQrCodeScanned(result.text)
|
onQrCodeScanned(result.text)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Don't print anything
|
// Don't do anything
|
||||||
} finally {
|
} finally {
|
||||||
image.close()
|
image.close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
|
|
||||||
private val DarkColorScheme = darkColorScheme(
|
private val DarkColorScheme = darkColorScheme(
|
||||||
primary = Purple80,
|
primary = Purple80,
|
||||||
|
@ -52,7 +51,6 @@ fun QScanTheme(
|
||||||
if (!view.isInEditMode) {
|
if (!view.isInEditMode) {
|
||||||
SideEffect {
|
SideEffect {
|
||||||
(view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
|
(view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
|
||||||
ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">QScan</string>
|
<string name="app_name">QScan</string>
|
||||||
|
<string name="should_auto_open_key">AUTO_OPEN</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1,5 +1,5 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "7.4.1" apply false
|
id("com.android.application") version "7.4.1" apply false
|
||||||
id("com.android.library") version "7.4.1" apply false
|
id("com.android.library") version "7.4.1" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.7.0" apply false
|
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
|
||||||
}
|
}
|
Reference in a new issue