fixed some warnings

This commit is contained in:
Zyzf 2023-11-16 20:52:35 +04:00
parent 7472b31ba2
commit 534babe2ea
11 changed files with 192 additions and 40 deletions

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_3a_API_25.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-11-16T12:43:19.045949464Z" />
</component>
</project>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">

View File

@ -60,15 +60,21 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
// UI // UI
implementation("androidx.activity:activity-compose:1.8.0") implementation("androidx.activity:activity-compose:1.8.1")
implementation(platform("androidx.compose:compose-bom:2023.10.01")) implementation(platform("androidx.compose:compose-bom:2023.10.01"))
implementation("androidx.navigation:navigation-compose:2.7.4") implementation("androidx.navigation:navigation-compose:2.7.5")
implementation("androidx.compose.ui:ui:1.6.0-alpha08") implementation("androidx.compose.ui:ui:1.6.0-beta01")
implementation("androidx.compose.ui:ui-graphics:1.6.0-alpha08") implementation("androidx.compose.ui:ui-graphics:1.6.0-beta01")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-alpha08") implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta01")
implementation("androidx.compose.material3:material3:1.2.0-alpha10") implementation("androidx.compose.material3:material3:1.2.0-alpha11")
implementation("io.coil-kt:coil-compose:2.4.0") // Retrofit
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("io.coil-kt:coil-compose:2.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.1")
implementation("com.jcraft:jsch:0.1.55")
// Room // Room
implementation("androidx.room:room-runtime:2.6.0") implementation("androidx.room:room-runtime:2.6.0")
@ -82,9 +88,9 @@ dependencies {
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01")) androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.0-alpha08") androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.0-beta01")
debugImplementation("androidx.compose.ui:ui-tooling:1.6.0-alpha08") debugImplementation("androidx.compose.ui:ui-tooling:1.6.0-beta01")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.0-alpha08") debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.0-beta01")
} }

View File

@ -4,6 +4,8 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="com.google.android.gms.persmission.AD_ID" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
@ -17,11 +19,9 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.CoffeePreorder"> android:theme="@style/Theme.CoffeePreorder">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>

View File

@ -2,13 +2,23 @@ package com.zyzf.coffeepreorder.coffee.composeui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.StrictMode
import android.os.StrictMode.ThreadPolicy
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
@ -17,6 +27,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
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.Add import androidx.compose.material.icons.filled.Add
@ -54,17 +65,31 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import coil.compose.AsyncImage import coil.compose.AsyncImage
import coil.request.ImageRequest import coil.request.ImageRequest
import com.jcraft.jsch.Channel
import com.jcraft.jsch.ChannelSftp
import com.jcraft.jsch.JSch
import com.jcraft.jsch.JSchException
import com.jcraft.jsch.Session
import com.jcraft.jsch.SftpException
import com.zyzf.coffeepreorder.R import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.database.AppDatabase import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.Properties
@SuppressLint("UnrememberedMutableState") @SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
DelicateCoroutinesApi::class
)
@Composable @Composable
fun CoffeeList(navController: NavController?) { fun CoffeeList(navController: NavController?) {
val openDialog = remember { mutableStateOf(false) } val openDialog = remember { mutableStateOf(false) }
@ -72,6 +97,20 @@ fun CoffeeList(navController: NavController?) {
val coffee = remember { mutableStateOf(Coffee("", 0.0, "", null,0)) } val coffee = remember { mutableStateOf(Coffee("", 0.0, "", null,0)) }
val context = LocalContext.current val context = LocalContext.current
val itemsList = remember { mutableStateListOf<Coffee>() } val itemsList = remember { mutableStateListOf<Coffee>() }
var imageUri: Any? by remember { mutableStateOf(R.drawable.img) }
val photoPicker = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia()
) {
if (it != null) {
Log.d("PhotoPicker", "Selected URI: $it")
imageUri = it
} else {
Log.d("PhotoPicker", "No media selected")
}
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).coffeeDao().getAll().collect { data -> AppDatabase.getInstance(context).coffeeDao().getAll().collect { data ->
@ -90,13 +129,15 @@ fun CoffeeList(navController: NavController?) {
horizontalArrangement = Arrangement.SpaceAround) { horizontalArrangement = Arrangement.SpaceAround) {
AsyncImage( AsyncImage(
model = ImageRequest.Builder(context = LocalContext.current).data("http://109.197.199.134/s/zXgFRTmbR4KMxMH/download?path=%2F&files=coffee_image" + coffee.value.uid + ".png") model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + currentCoffee.uid +".png")
.crossfade(true).build(), .crossfade(true).build(),
error = painterResource(R.drawable.ic_broken_image), error = painterResource(R.drawable.ic_broken_image),
placeholder = painterResource(R.drawable.loading_img), placeholder = painterResource(R.drawable.loading_img),
contentDescription = "Кофе", contentDescription = "Кофе",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxHeight().weight(1f) modifier = Modifier
.size(100.dp)
.clip(RoundedCornerShape(50.dp))
) )
Column( Column(
@ -187,26 +228,66 @@ fun CoffeeList(navController: NavController?) {
}, },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal) keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal)
) )
OutlinedTextField(modifier = Modifier.fillMaxWidth(), OutlinedTextField(modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp),
value = ingredients, onValueChange = {ingredients = it}, value = ingredients, onValueChange = {ingredients = it},
label = { label = {
Text(stringResource(id = R.string.coffee_ingredients)) Text(stringResource(id = R.string.coffee_ingredients))
}, },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
) )
AsyncImage(
modifier = Modifier
.size(100.dp).clip(RoundedCornerShape(50.dp)).border(2.dp, MaterialTheme.colorScheme.outline, shape = RoundedCornerShape(50.dp))
.clickable {
photoPicker.launch(
PickVisualMediaRequest(
ActivityResultContracts.PickVisualMedia.ImageOnly
)
)
}.border(2.dp, MaterialTheme.colorScheme.outlineVariant, shape = RoundedCornerShape(50.dp)),
contentDescription = "Кофе",
error = painterResource(R.drawable.ic_broken_image),
placeholder = painterResource(R.drawable.loading_img),
contentScale = ContentScale.Crop,
model = ImageRequest.Builder(LocalContext.current)
.data(if (coffee.value.name != "") "https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.value.uid +".png" else imageUri)
.crossfade(enable = true)
.build(),
)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
if (add.value) { if (add.value) {
Button(onClick = { Button(onClick = {
GlobalScope.launch (Dispatchers.Main) { GlobalScope.launch (Dispatchers.Main) {
AppDatabase.getInstance(context).coffeeDao().insert( val newCoffee: Long = AppDatabase.getInstance(context).coffeeDao().insert(
Coffee(name = name, cost = cost, ingredients = ingredients, cartId = null, 0) name = name, cost = cost, ingredients = ingredients
) )
val inputStream = context.contentResolver.openInputStream(imageUri as Uri)
val bitmap = BitmapFactory.decodeStream(inputStream)
val f = File(context.cacheDir, "coffee_image_$newCoffee.png")
withContext(Dispatchers.IO) {
f.createNewFile()
val bos = ByteArrayOutputStream()
bitmap.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos)
val bitmapdata = bos.toByteArray()
val fos = FileOutputStream(f)
fos.write(bitmapdata)
fos.flush()
fos.close()
}
copyFileToSftp(f, "/mnt/nextcloud/data/Zyzf/files/Images")
AppDatabase.getInstance(context).coffeeDao().getAll().collect { data -> AppDatabase.getInstance(context).coffeeDao().getAll().collect { data ->
itemsList.clear() itemsList.clear()
itemsList.addAll(data) itemsList.addAll(data)
} }
} }
}) { }, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Добавить") Text("Добавить")
} }
} else { } else {
@ -221,7 +302,7 @@ fun CoffeeList(navController: NavController?) {
} }
} }
}) { }, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Изменить") Text("Изменить")
} }
Spacer(modifier = Modifier.padding(all = 20.dp)) Spacer(modifier = Modifier.padding(all = 20.dp))
@ -236,7 +317,7 @@ fun CoffeeList(navController: NavController?) {
} }
} }
}) { }, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Удалить") Text("Удалить")
} }
} }
@ -246,6 +327,48 @@ fun CoffeeList(navController: NavController?) {
} }
} }
val REMOTE_HOST = "109.197.199.134"
val USERNAME = "zyzf"
val PASSWORD = "250303Zyzf-d-grad"
val REMOTE_PORT = 2223
fun copyFileToSftp(srcFile: File, ftpPath: String): Boolean {
var jschSession: Session? = null
try {
val jsch = JSch()
jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts")
jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT)
jschSession.setPassword(PASSWORD)
val config = Properties()
config["StrictHostKeyChecking"] = "no"
jschSession.setConfig(config)
val policy = ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
jschSession.connect(10000)
val sftp: Channel = jschSession.openChannel("sftp")
sftp.connect(5000)
val channelSftp: ChannelSftp = sftp as ChannelSftp
channelSftp.put(srcFile.absolutePath, ftpPath)
channelSftp.exit()
} catch (e: JSchException) {
e.printStackTrace()
return false
} catch (e: SftpException) {
e.printStackTrace()
return false
} finally {
jschSession?.disconnect()
}
return true
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable @Composable

View File

@ -42,11 +42,13 @@ import com.zyzf.coffeepreorder.composeui.navigation.Screen
import com.zyzf.coffeepreorder.database.AppDatabase import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@OptIn(DelicateCoroutinesApi::class)
@Composable @Composable
fun Login(navController: NavController?) { fun Login(navController: NavController?) {
val context = LocalContext.current val context = LocalContext.current
@ -59,14 +61,15 @@ fun Login(navController: NavController?) {
} }
Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) { Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) {
AsyncImage( AsyncImage(
model = ImageRequest.Builder(context = LocalContext.current).data("http://109.197.199.134/s/zXgFRTmbR4KMxMH/download?path=%2F&files=coffee_image.png") model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/YsHjPo3NDmoptSk/download/coffee_image.png")
.crossfade(true).build(), .crossfade(true).build(),
error = painterResource(R.drawable.ic_broken_image), error = painterResource(R.drawable.ic_broken_image),
placeholder = painterResource(R.drawable.loading_img), placeholder = painterResource(R.drawable.loading_img),
contentDescription = "Кофе", contentDescription = "Кофе",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
modifier = Modifier modifier = Modifier.size(100.dp)
) )
Spacer(modifier = Modifier.padding(all = 20.dp)) Spacer(modifier = Modifier.padding(all = 20.dp))
OutlinedTextField(modifier = Modifier.fillMaxWidth(), OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = login, onValueChange = {login = it}, value = login, onValueChange = {login = it},

View File

@ -47,17 +47,17 @@ abstract class AppDatabase : RoomDatabase() {
val coffee9 = Coffee("Coffee9", 200.0, "Ing1", null, 0) val coffee9 = Coffee("Coffee9", 200.0, "Ing1", null, 0)
val coffee10 = Coffee("Coffee10", 900.0, "Ing1", null, 0) val coffee10 = Coffee("Coffee10", 900.0, "Ing1", null, 0)
val coffee11 = Coffee("Coffee11", 200.0, "Ing1", null, 0) val coffee11 = Coffee("Coffee11", 200.0, "Ing1", null, 0)
coffeeDao.insert(coffee1) coffeeDao.insert(coffee1.name, coffee1.cost, coffee1.ingredients)
coffeeDao.insert(coffee2) coffeeDao.insert(coffee2.name, coffee2.cost, coffee2.ingredients)
coffeeDao.insert(coffee3) coffeeDao.insert(coffee3.name, coffee3.cost, coffee3.ingredients)
coffeeDao.insert(coffee4) coffeeDao.insert(coffee4.name, coffee4.cost, coffee4.ingredients)
coffeeDao.insert(coffee5) coffeeDao.insert(coffee5.name, coffee5.cost, coffee5.ingredients)
coffeeDao.insert(coffee6) coffeeDao.insert(coffee6.name, coffee6.cost, coffee6.ingredients)
coffeeDao.insert(coffee7) coffeeDao.insert(coffee7.name, coffee7.cost, coffee7.ingredients)
coffeeDao.insert(coffee8) coffeeDao.insert(coffee8.name, coffee8.cost, coffee8.ingredients)
coffeeDao.insert(coffee9) coffeeDao.insert(coffee9.name, coffee9.cost, coffee9.ingredients)
coffeeDao.insert(coffee10) coffeeDao.insert(coffee10.name, coffee10.cost, coffee10.ingredients)
coffeeDao.insert(coffee11) coffeeDao.insert(coffee11.name, coffee11.cost, coffee11.ingredients)
// Cart // Cart
val cartDao = database.cartDao() val cartDao = database.cartDao()
val cart = Cart() val cart = Cart()

View File

@ -2,7 +2,6 @@ package com.zyzf.coffeepreorder.database.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import androidx.room.Update import androidx.room.Update
import com.zyzf.coffeepreorder.database.model.Coffee import com.zyzf.coffeepreorder.database.model.Coffee
@ -17,8 +16,8 @@ interface CoffeeDao {
@Query("select coffee.uid, name, cost, ingredients, cart_id, count, cart.uid as cart_uid from coffee left join cart on coffee.cart_id = cart.uid where coffee.uid = :uid") @Query("select coffee.uid, name, cost, ingredients, cart_id, count, cart.uid as cart_uid from coffee left join cart on coffee.cart_id = cart.uid where coffee.uid = :uid")
suspend fun getByUid(uid: Int): CoffeeWithCart suspend fun getByUid(uid: Int): CoffeeWithCart
@Insert @Query("insert into coffee (name, cost, ingredients, count) values (:name, :cost, :ingredients, 0)")
suspend fun insert(coffee: Coffee) suspend fun insert(name: String, cost: Double, ingredients: String): Long
@Update @Update
suspend fun update(coffee: Coffee) suspend fun update(coffee: Coffee)

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
</selector>

View File

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id("com.android.application") version "8.1.2" apply false id("com.android.application") version "8.1.3" apply false
id("org.jetbrains.kotlin.android") version "1.9.10" apply false id("org.jetbrains.kotlin.android") version "1.9.10" apply false
id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false id("com.google.devtools.ksp") version "1.9.10-1.0.13" apply false
} }

View File

@ -10,6 +10,7 @@ dependencyResolutionManagement {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven { setUrl("https://jitpack.io") }
} }
} }