Requests added

This commit is contained in:
leca 2024-10-12 04:37:32 +03:00
parent 3bfad0f6ad
commit 4cad738f0e
11 changed files with 137 additions and 70 deletions

View File

@ -34,7 +34,6 @@ android {
viewBinding = true viewBinding = true
} }
} }
var cameraxVersion = "1.0.1"
dependencies { dependencies {
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
@ -49,7 +48,9 @@ dependencies {
implementation(libs.androidx.legacy.support.v4) implementation(libs.androidx.legacy.support.v4)
implementation(libs.androidx.fragment) implementation(libs.androidx.fragment)
testImplementation(libs.junit) testImplementation(libs.junit)
implementation(libs.volley)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
implementation (libs.play.services.code.scanner)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
// implementation("com.google.android.material:1.2.0") // implementation("com.google.android.material:1.2.0")
@ -58,8 +59,8 @@ dependencies {
implementation (libs.barcode.scanning) implementation (libs.barcode.scanning)
// CameraX library // CameraX library
implementation ("androidx.camera:camera-camera2:$cameraxVersion") implementation (libs.androidx.camera.camera2)
implementation ("androidx.camera:camera-lifecycle:$cameraxVersion") implementation (libs.androidx.camera.lifecycle)
implementation (libs.androidx.camera.view) implementation (libs.androidx.camera.view)
implementation ("com.google.android.gms:play-services-code-scanner:16.1.0")
} }

View File

@ -12,6 +12,7 @@
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application <application
android:allowBackup="true" android:allowBackup="true"

View File

@ -11,6 +11,7 @@ import java.io.File
object AbstractProductContract { object AbstractProductContract {
object AbstractProductEntry : BaseColumns { object AbstractProductEntry : BaseColumns {
const val TABLE_NAME = "abstract_products" const val TABLE_NAME = "abstract_products"
const val BARCODE = "barcode"
const val PRODUCT_NAME = "name" const val PRODUCT_NAME = "name"
const val PRODUCT_NET_WEIGHT = "net_weight" const val PRODUCT_NET_WEIGHT = "net_weight"
const val IMAGE_FILENAME = "image_filename" const val IMAGE_FILENAME = "image_filename"
@ -38,6 +39,7 @@ object ProductContract {
const val SQL_CREATE_ABSTRACT_PRODUCTS_TABLE = const val SQL_CREATE_ABSTRACT_PRODUCTS_TABLE =
"CREATE TABLE ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} (" + "CREATE TABLE ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} (" +
"${BaseColumns._ID} INTEGER PRIMARY KEY," + "${BaseColumns._ID} INTEGER PRIMARY KEY," +
"${AbstractProductContract.AbstractProductEntry.BARCODE} TEXT," +
"${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} TEXT," + "${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} TEXT," +
"${AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT} REAL," + "${AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT} REAL," +
"${AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME} TEXT," + "${AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME} TEXT," +
@ -101,6 +103,7 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
var result = mutableListOf<AbstractProduct>() var result = mutableListOf<AbstractProduct>()
val projection = arrayOf( val projection = arrayOf(
BaseColumns._ID, BaseColumns._ID,
AbstractProductContract.AbstractProductEntry.BARCODE,
AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, AbstractProductContract.AbstractProductEntry.PRODUCT_NAME,
AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME, AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME,
AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT,
@ -114,11 +117,12 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
with(cursor) { with(cursor) {
while (moveToNext()) { while (moveToNext()) {
val abstractProductId = getInt(getColumnIndexOrThrow(BaseColumns._ID)) val abstractProductId = getInt(getColumnIndexOrThrow(BaseColumns._ID))
val abstractProductBarcode = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.BARCODE))
val abstractProductName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME)) val abstractProductName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
val abstractProductNetWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT)) val abstractProductNetWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
val abstractProductImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME)) val abstractProductImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
val abstractProduct = AbstractProduct(abstractProductId, abstractProductName, abstractProductNetWeight, abstractProductImageHash, category = id) val abstractProduct = AbstractProduct(abstractProductId, abstractProductBarcode, abstractProductName, abstractProductNetWeight, abstractProductImageHash, category = id)
result.add(abstractProduct) result.add(abstractProduct)
} }

View File

@ -2,46 +2,57 @@ package org.foxarmy.barcodescannerforemployees
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
class Parser constructor(payloadStartRegex: String, payloadEndRegex: String, payloadRegex: String){ class Parser constructor() {
val payloadStartRegex: String = payloadStartRegex fun parse(text: String): AbstractProduct {
val payloadEndRegex: String = payloadEndRegex var text = text
val payloadRegex: String = payloadRegex
fun parse(text: String): MutableList<AbstractProduct> { var name = ""
var netWeight = 0.0
val payloadStart = Regex(payloadStartRegex) //Find volume in liters
val payloadEnd = Regex(payloadEndRegex) val litersRegex = Regex("[0-9+],[0-9*]\\s*[лЛ]")
val payload = Regex(payloadRegex) val foundLiters = litersRegex.find(text)
if (foundLiters != null) {
val startFound = payloadStart.find(text)?.value.toString() text = text.replace(foundLiters.groupValues[0], "")
val payloadStartIndex = text.indexOf(startFound) netWeight = stripNetWeight(foundLiters.groupValues[0])
var clearText = text.removeRange( } else { // not found liters. Maybe milliliters?
0, val millilitersRegex = Regex("[0-9+],[0-9*]\\s*((мл)|(МЛ)|(Мл))")
if (payloadStartIndex < 0) 0 else payloadStartIndex val foundMilliliters = millilitersRegex.find(text)
) netWeight = if (foundMilliliters != null) {
text = text.replace(foundMilliliters.groupValues[0], "")
val endFound = payloadEnd.find(clearText)?.value.toString() stripNetWeight(foundMilliliters.groupValues[0]) / 1000 // Found milliliters, convert to liters
val payloadEndIndex = clearText.indexOf(endFound) } else {
clearText = clearText.removeRange( 0.0 // Nothing found
if (payloadEndIndex < 0) 0 else payloadEndIndex - 1, }
clearText.length
)
println(clearText)
var products = payload.findAll(clearText).toMutableList()
for (product in products) {
println(product.value)
} }
return mutableListOf() val kilogramRegex = Regex("[0-9+],[0-9*]\\s*((кг)|(Кг))")
val foundKilograms = kilogramRegex.find(text)
if (foundKilograms != null) {
text = text.replace(foundKilograms.groupValues[0], "")
netWeight = stripNetWeight(foundKilograms.groupValues[0]) * 1000
} else { // Not found kilograms, maybe we could find grams?
val gramsRegex = Regex("[0-9+],[0-9*]\\s*[гГ]")
val foundGrams = gramsRegex.find(text)
netWeight = if (foundGrams != null) {
text = text.replace(foundGrams.groupValues[0], "")
stripNetWeight(foundGrams.groupValues[0])
} else {
0.0 // Nothing found
}
}
val piecesRegex = Regex("[0-9+],*[0-9*]\\s*((шт)|(Шт))")
val foundPieces = piecesRegex.find(text)
if (foundPieces != null) {
text = text.replace(foundPieces.groupValues[0], "")
netWeight = stripNetWeight(foundPieces.groupValues[0])
} else {
netWeight = 0.0
}
name = text
return AbstractProduct(0, "", name, netWeight, "", 0)
} }
} }
fun main () {
val p = Parser("""\<table\s*class\=\"randomBarcodes\"\s*>""", """\<\/table\>""", """[ёЁ\u0401\u0451\u0410-\u044f\d\w\s]{16,}""")
p.parse(Requester("https://barcode-list.ru", "barcode/RU/Поиск.htm?barcode=4680036915828", ).request("4680036915828"))
// println(Requester("https://barcode-list.ru", "barcode/RU/Поиск.htm?barcode=4680036915828", ).request("4680036915828"))
}

View File

@ -1,28 +1,35 @@
package org.foxarmy.barcodescannerforemployees package org.foxarmy.barcodescannerforemployees
import java.net.HttpURLConnection import android.content.Context
import java.net.URL import android.widget.Toast
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
class Requester constructor(siteName:String, endpoint: String) { class Requester constructor(var siteName: String, var endpoint: String) {
var siteName: String = siteName var response = ""
var endpoint: String = endpoint
fun request (productId: String): String { fun request(context: Context, barcode: String) {
val url = URL("${siteName}/$endpoint") val url = "${siteName}/${endpoint}"
var response: String = "" val volleyQueue = Volley.newRequestQueue(context)
val stringRequest = object: StringRequest(
Method.POST, url, { resp ->
run {
response = resp
}
},
{
Toast.makeText(context, "Cannot make request", Toast.LENGTH_LONG).show()
}
) {
override fun getHeaders(): Map<String, String> {
return mapOf("referer" to "$siteName/")
}
with(url.openConnection() as HttpURLConnection) { public override fun getParams(): MutableMap<String, String> {
requestMethod = "GET" // optional default is GET return mutableMapOf("barcode" to barcode)
println("\nSent 'GET' request to URL : $url; Response Code : $responseCode")
inputStream.bufferedReader().use {
it.lines().forEach { line ->
response += line //+ '\n'
} }
} }
} volleyQueue.add(stringRequest)
return response
} }
} }

View File

@ -6,12 +6,14 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.graphics.scale import androidx.core.graphics.scale
import com.google.firebase.components.BuildConfig import com.google.firebase.components.BuildConfig
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.net.URLEncoder
import java.security.MessageDigest import java.security.MessageDigest
fun getImageUri(activity: Activity, imageFile: File): Uri? { fun getImageUri(activity: Activity, imageFile: File): Uri? {
@ -40,3 +42,18 @@ fun String.md5(): String {
val digest = md.digest(this.toByteArray()) val digest = md.digest(this.toByteArray())
return digest.toHexString() return digest.toHexString()
} }
fun stripNetWeight (netWeight: String): Double {
return removeSubstringsFromString(netWeight, arrayOf("Л", "л", "мл", "Мл", "г", "Г", "кг", "Кг", "шт", "Шт", ",", " ", ".")).toDouble()
}
fun removeSubstringsFromString(text: String, toRemove: Array<String>): String {
var result = text
for (candidate in toRemove.iterator()) {
result = result.replace(candidate, "")
}
Log.d("QWERTYUIOP", result)
return result
}
fun String.utf8(): String = URLEncoder.encode(this, "UTF-8")

View File

@ -18,6 +18,7 @@ import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
import java.io.File import java.io.File
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.StandardCopyOption import java.nio.file.StandardCopyOption
import kotlin.concurrent.thread
class AddAbstractProductActivity : AppCompatActivity() { class AddAbstractProductActivity : AppCompatActivity() {
private lateinit var imageView: ImageView private lateinit var imageView: ImageView
@ -34,6 +35,7 @@ class AddAbstractProductActivity : AppCompatActivity() {
private var abstractProduct: AbstractProduct? = null private var abstractProduct: AbstractProduct? = null
private lateinit var pictureFile: File private lateinit var pictureFile: File
private lateinit var picturesPath: File private lateinit var picturesPath: File
private lateinit var barcode: String
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -73,7 +75,7 @@ class AddAbstractProductActivity : AppCompatActivity() {
saveButton.setOnClickListener { saveButton.setOnClickListener {
val productName = productNameText.text.toString() val productName = productNameText.text.toString()
val netWeight = netWeightText.text val netWeight = netWeightText.text
if (!this::pictureFile.isInitialized && !pictureFile.exists()) { if (!this::pictureFile.isInitialized || !pictureFile.exists()) {
Toast.makeText(this, "Please, make a picture of a product!", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Please, make a picture of a product!", Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
@ -89,6 +91,7 @@ class AddAbstractProductActivity : AppCompatActivity() {
val db = DBStorageController(this).writableDatabase val db = DBStorageController(this).writableDatabase
val values = ContentValues().apply { val values = ContentValues().apply {
put(AbstractProductContract.AbstractProductEntry.BARCODE, barcode)
put(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, productName) put(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, productName)
put(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, netWeight.toString()) put(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, netWeight.toString())
put(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME, pictureFile.nameWithoutExtension) put(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME, pictureFile.nameWithoutExtension)
@ -117,7 +120,21 @@ class AddAbstractProductActivity : AppCompatActivity() {
val scanner = GmsBarcodeScanning.getClient(this) val scanner = GmsBarcodeScanning.getClient(this)
scanner.startScan() scanner.startScan()
.addOnSuccessListener { barcode -> .addOnSuccessListener { barcode ->
productNameText.setText(barcode.rawValue) this.barcode = barcode.rawValue.toString()
val requester = Requester("https://ean-online.ru", "match.php")
requester.request(this, barcode.rawValue!!.toString())
var abstractProduct: AbstractProduct
thread {
// Я сам в ахуях какой это костыль, пока хз как фиксить, потом придумаю :))
while (requester.response == "") { }
abstractProduct = Parser().parse(requester.response)
requester.response = ""
runOnUiThread {
productNameText.text = abstractProduct.name
netWeightText.text = abstractProduct.netWeight.toString()
}
}
} }
.addOnFailureListener { e -> .addOnFailureListener { e ->
Toast.makeText( Toast.makeText(

View File

@ -5,13 +5,15 @@ import android.os.Parcelable
class AbstractProduct() : Parcelable { class AbstractProduct() : Parcelable {
var id: Int = 0 var id: Int = 0
var barcode: String = ""
var name: String = "" var name: String = ""
var netWeight: Double = 0.0 var netWeight: Double = 0.0
var imageHash: String = "" var imageHash: String = ""
var category: Int = 0 var category: Int = 0
constructor(id: Int, name: String ,netWeight: Double, imageHash: String, category: Int) : this() { constructor(id: Int, barcode: String, name: String ,netWeight: Double, imageHash: String, category: Int) : this() {
this.id = id this.id = id
this.barcode = barcode
this.name = name this.name = name
this.netWeight = netWeight this.netWeight = netWeight
this.imageHash = imageHash this.imageHash = imageHash
@ -20,6 +22,7 @@ class AbstractProduct() : Parcelable {
constructor(parcel: Parcel) : this() { constructor(parcel: Parcel) : this() {
id = parcel.readInt() id = parcel.readInt()
barcode = parcel.readString()!!
name = parcel.readString()!! name = parcel.readString()!!
netWeight = parcel.readDouble() netWeight = parcel.readDouble()
imageHash = parcel.readString()!! imageHash = parcel.readString()!!
@ -28,6 +31,7 @@ class AbstractProduct() : Parcelable {
override fun writeToParcel(parcel: Parcel, flags: Int) { override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(id) parcel.writeInt(id)
parcel.writeString(barcode)
parcel.writeString(name) parcel.writeString(name)
parcel.writeDouble(netWeight) parcel.writeDouble(netWeight)
parcel.writeString(imageHash) parcel.writeString(imageHash)
@ -47,5 +51,4 @@ class AbstractProduct() : Parcelable {
return arrayOfNulls(size) return arrayOfNulls(size)
} }
} }
} }

View File

@ -76,6 +76,7 @@ class StorageFragment : Fragment() {
val db = DBStorageController(requireContext()).readableDatabase val db = DBStorageController(requireContext()).readableDatabase
val projection = arrayOf(BaseColumns._ID, val projection = arrayOf(BaseColumns._ID,
AbstractProductContract.AbstractProductEntry.BARCODE,
AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, AbstractProductContract.AbstractProductEntry.PRODUCT_NAME,
AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT,
AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME, AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME,
@ -87,12 +88,13 @@ class StorageFragment : Fragment() {
with (cursor) { with (cursor) {
while(moveToNext()) { while(moveToNext()) {
val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID)) val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID))
val barcode = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.BARCODE))
val productName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME)) val productName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
val netWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT)) val netWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
val productImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME)) val productImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
val category = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.CATEGORY)) val category = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.CATEGORY))
val product = AbstractProduct(productId, productName, netWeight, productImageHash, category) val product = AbstractProduct(productId, barcode, productName, netWeight, productImageHash, category)
generateThumbnailForImage(context!!, productImageHash) generateThumbnailForImage(context!!, productImageHash)

View File

@ -11,10 +11,10 @@ import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
import org.foxarmy.barcodescannerforemployees.DBStorageController import org.foxarmy.barcodescannerforemployees.DBStorageController
import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.activities.FullscreenActivity import org.foxarmy.barcodescannerforemployees.activities.FullscreenActivity
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
import org.foxarmy.barcodescannerforemployees.getImageUri import org.foxarmy.barcodescannerforemployees.getImageUri
import java.io.File import java.io.File
@ -59,8 +59,6 @@ class AbstractProductView: LinearLayout {
} }
productNameField.text = abstractProduct.name productNameField.text = abstractProduct.name
netWeightField.text = abstractProduct.netWeight.toString() netWeightField.text = abstractProduct.netWeight.toString()
categoryField.text = DBStorageController(context).getCategoryNameById(DBStorageController(context).readableDatabase, abstractProduct.category) categoryField.text = DBStorageController(context).getCategoryNameById(DBStorageController(context).readableDatabase, abstractProduct.category)

View File

@ -17,8 +17,12 @@ gridlayout = "1.0.0"
activity = "1.9.2" activity = "1.9.2"
legacySupportV4 = "1.0.0" legacySupportV4 = "1.0.0"
fragment = "1.8.4" fragment = "1.8.4"
playServicesCodeScanner = "16.1.0"
volley = "1.2.1"
[libraries] [libraries]
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraView" }
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "cameraView" }
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraView" } androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraView" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "barcodeScanning" } barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "barcodeScanning" }
@ -35,6 +39,8 @@ androidx-gridlayout = { group = "androidx.gridlayout", name = "gridlayout", vers
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacySupportV4" } androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacySupportV4" }
androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" } androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" }
play-services-code-scanner = { module = "com.google.android.gms:play-services-code-scanner", version.ref = "playServicesCodeScanner" }
volley = { module = "com.android.volley:volley", version.ref = "volley" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }