started 4 lab

This commit is contained in:
Zyzf 2023-12-03 18:03:39 +04:00
parent e3e4d1cacb
commit 889e80ad9e
36 changed files with 942 additions and 730 deletions

View File

@ -1,17 +1,10 @@
<?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" />
<value>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>

View File

@ -4,16 +4,15 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.10" />
<option name="version" value="1.9.20" />
</component>
</project>

10
.idea/migrations.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

View File

@ -41,7 +41,7 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.3"
kotlinCompilerExtensionVersion = "1.5.5"
}
packaging {
resources {
@ -63,34 +63,32 @@ dependencies {
implementation("androidx.activity:activity-compose:1.8.1")
implementation(platform("androidx.compose:compose-bom:2023.10.01"))
implementation("androidx.navigation:navigation-compose:2.7.5")
implementation("androidx.compose.ui:ui:1.6.0-beta01")
implementation("androidx.compose.ui:ui-graphics:1.6.0-beta01")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta01")
implementation("androidx.compose.material3:material3:1.2.0-alpha11")
implementation("androidx.compose.ui:ui:1.6.0-beta02")
implementation("androidx.compose.ui:ui-graphics:1.6.0-beta02")
implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-beta02")
implementation("androidx.compose.material3:material3:1.2.0-alpha12")
// 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("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("com.jcraft:jsch:0.1.55")
// Room
implementation("androidx.room:room-runtime:2.6.0")
annotationProcessor("androidx.room:room-compiler:2.6.0")
ksp("androidx.room:room-compiler:2.6.0")
implementation("androidx.room:room-ktx:2.6.0")
implementation("androidx.room:room-paging:2.6.0")
implementation("androidx.room:room-runtime:2.6.1")
annotationProcessor("androidx.room:room-compiler:2.6.1")
ksp("androidx.room:room-compiler:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
implementation("androidx.room:room-paging:2.6.1")
// Tests
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.0-beta01")
debugImplementation("androidx.compose.ui:ui-tooling:1.6.0-beta01")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.0-beta01")
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.0-beta02")
debugImplementation("androidx.compose.ui:ui-tooling:1.6.0-beta02")
debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.0-beta02")
}

View File

@ -0,0 +1,14 @@
package com.zyzf.coffeepreorder
import android.app.Application
import com.zyzf.coffeepreorder.database.AppContainer
import com.zyzf.coffeepreorder.database.AppDataContainer
class CoffeeApplication : Application() {
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
container = AppDataContainer(this)
}
}

View File

@ -10,7 +10,7 @@ import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.zyzf.coffeepreorder.composeui.navigation.MainNavbar
import com.zyzf.coffeepreorder.ui.navigation.MainNavbar
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
class MainActivity : ComponentActivity() {

View File

@ -1,390 +0,0 @@
package com.zyzf.coffeepreorder.coffee.composeui
import android.annotation.SuppressLint
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.border
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.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.outlined.Create
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import coil.compose.AsyncImage
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.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.Properties
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
DelicateCoroutinesApi::class
)
@Composable
fun CoffeeList(navController: NavController?) {
val openDialog = remember { mutableStateOf(false) }
val add = remember { mutableStateOf(false) }
val coffee = remember { mutableStateOf(Coffee("", 0.0, "", null, 0)) }
val context = LocalContext.current
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) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).coffeeDao().getAll().collect { data ->
itemsList.clear()
itemsList.addAll(data)
}
}
}
LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally) {
items(itemsList) { currentCoffee ->
Row(modifier = Modifier
.fillMaxWidth()
.heightIn(max = 140.dp)
.padding(bottom = 10.dp, top = 10.dp),
horizontalArrangement = Arrangement.SpaceAround) {
AsyncImage(
model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + currentCoffee.uid +".png")
.crossfade(true).build(),
error = painterResource(R.drawable.ic_broken_image),
placeholder = painterResource(R.drawable.loading_img),
contentDescription = "Кофе",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(100.dp)
.clip(RoundedCornerShape(50.dp))
)
Column(
Modifier
.weight(2f)
.padding(start = 20.dp)) {
Text(text = currentCoffee.name, fontSize = 25.sp)
Text(text = String.format("%.2f", currentCoffee.cost), fontSize = 20.sp)
Text(text = currentCoffee.ingredients, fontSize = 15.sp)
Row(
Modifier
.fillMaxWidth()
.padding(top = 5.dp)) {
Button(
onClick = {
GlobalScope.launch (Dispatchers.Main) {
currentCoffee.uid?.let {
AppDatabase.getInstance(context).cartDao().get().uid?.let { it1 ->
AppDatabase.getInstance(context).cartDao().insertCoffee(
it1,
it,
1
)
}
}
AppDatabase.getInstance(context).coffeeDao().getAll().collect { data ->
itemsList.clear()
itemsList.addAll(data)
}
}
},
shape = CircleShape,
modifier = Modifier.fillMaxWidth(fraction = 0.75f)
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(text = "В корзину")
}
OutlinedIconButton(
onClick = {
coffee.value = currentCoffee
add.value = false
openDialog.value = true
},
Modifier
.padding(start = 10.dp)
.clip(CircleShape)) {
Icon(
imageVector = Icons.Outlined.Create,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
}
}
}
}
}
}
Box(modifier = Modifier.fillMaxSize()) {
FloatingActionButton(onClick = { coffee.value = Coffee("", 0.0, "", null, 0); add.value = true; openDialog.value = true },
Modifier
.padding(all = 20.dp)
.align(alignment = Alignment.BottomEnd)) {
Icon(
imageVector = Icons.Filled.Add,
contentDescription = "Add",
modifier = Modifier.size(20.dp)
)
}
}
if (openDialog.value) {
var name by remember { mutableStateOf(coffee.value.name) }
var cost by remember { mutableDoubleStateOf(coffee.value.cost) }
var ingredients by remember { mutableStateOf(coffee.value.ingredients) }
ModalBottomSheet(onDismissRequest = { openDialog.value = false }) {
Column(modifier = Modifier
.fillMaxWidth()
.padding(all = 10.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = name, onValueChange = {name = it},
label = {
Text(stringResource(id = R.string.coffee_name))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
)
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = cost.toString(), onValueChange = {cost = it.toDouble()},
label = {
Text(stringResource(id = R.string.coffee_cost))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal)
)
OutlinedTextField(modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp),
value = ingredients, onValueChange = {ingredients = it},
label = {
Text(stringResource(id = R.string.coffee_ingredients))
},
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) {
if (add.value) {
Button(onClick = {
GlobalScope.launch (Dispatchers.Main) {
val newCoffee: Long = AppDatabase.getInstance(context).coffeeDao().insert(
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 ->
itemsList.clear()
itemsList.addAll(data)
}
openDialog.value = false
}
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Добавить")
}
} else {
Button(onClick = {
GlobalScope.launch (Dispatchers.Main) {
AppDatabase.getInstance(context).coffeeDao().update(
Coffee(name = name, cost = cost, ingredients = ingredients, cartId = coffee.value.cartId, count = coffee.value.count)
)
AppDatabase.getInstance(context).coffeeDao().getAll().collect { data ->
itemsList.clear()
itemsList.addAll(data)
}
}
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Изменить")
}
Spacer(modifier = Modifier.padding(all = 20.dp))
Button(onClick = {
GlobalScope.launch (Dispatchers.Main) {
AppDatabase.getInstance(context).coffeeDao().delete(
coffee.value
)
AppDatabase.getInstance(context).coffeeDao().getAll().collect { data ->
itemsList.clear()
itemsList.addAll(data)
}
openDialog.value = false
}
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Удалить")
}
}
}
}
}
}
}
const val REMOTE_HOST = "109.197.199.134"
const val USERNAME = "zyzf"
const val PASSWORD = "250303Zyzf-d-grad"
const 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 = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun CoffeeListPreview() {
CoffeePreorderTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
CoffeeList(navController = null)
}
}
}

View File

@ -1,72 +0,0 @@
package com.zyzf.coffeepreorder.coffee.composeui
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.coffee.model.getCoffee
import com.zyzf.coffeepreorder.composeui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CoffeeView(navController: NavController?, id: Int) {
val coffee = getCoffee()[id]
ModalBottomSheet(onDismissRequest = { navController?.navigate(Screen.CoffeeList.route) }) {
Column(modifier = Modifier.fillMaxWidth().padding(all = 10.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = coffee.name, onValueChange = {}, readOnly = true,
label = {
Text(stringResource(id = R.string.coffee_name))
}
)
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = coffee.cost.toString(), onValueChange = {}, readOnly = true,
label = {
Text(stringResource(id = R.string.coffee_cost))
}
)
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = coffee.ingredients, onValueChange = {}, readOnly = true,
label = {
Text(stringResource(id = R.string.coffee_ingredients))
}
)
Row(modifier = Modifier.fillMaxWidth()) {
Button(onClick = { navController?.navigate(Screen.CoffeeView.route) }) {
Text("Изменить")
}
}
}
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun StudentViewPreview() {
CoffeePreorderTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
CoffeeView(navController = null, id = 0)
}
}
}

View File

@ -1,27 +0,0 @@
package com.zyzf.coffeepreorder.coffee.model
import com.zyzf.coffeepreorder.R
import java.io.Serializable
data class Coffee(
val name: String,
val cost: Double,
val ingredients: String,
val image: Int
) : Serializable
fun getCoffee(): List<Coffee> {
return listOf(
Coffee("Coffee1", 200.0, "Ing1", R.drawable.coffee_image),
Coffee("Coffee2", 300.0, "Ing2", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image),
Coffee("Coffee3", 500.0, "Ing3", R.drawable.coffee_image)
)
}

View File

@ -1,152 +0,0 @@
package com.zyzf.coffeepreorder.composeui
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.composeui.navigation.Screen
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(DelicateCoroutinesApi::class)
@Composable
fun Login(navController: NavController?) {
val context = LocalContext.current
var login by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).userDao().getAll()
}
}
Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) {
AsyncImage(
model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/YsHjPo3NDmoptSk/download/coffee_image.png")
.crossfade(true).build(),
error = painterResource(R.drawable.ic_broken_image),
placeholder = painterResource(R.drawable.loading_img),
contentDescription = "Кофе",
contentScale = ContentScale.Crop,
modifier = Modifier.size(150.dp)
)
Spacer(modifier = Modifier.padding(all = 20.dp))
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = login, onValueChange = {login = it},
label = {
Text(stringResource(id = R.string.profile_login_label))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
)
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = password, onValueChange = {password = it},
label = {
Text(stringResource(id = R.string.profile_passw_label))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
visualTransformation = PasswordVisualTransformation()
)
Spacer(modifier = Modifier.padding(all = 20.dp))
Button(
onClick = {
var user: User?
GlobalScope.launch (Dispatchers.Main) {
user = AppDatabase.getInstance(context).userDao().tryLogin(login, password)
if (user != null) {
AppDatabase.getInstance(context).userDao().logout()
AppDatabase.getInstance(context).userDao().setLogined(user!!.uid!!)
navController?.navigate(Screen.CoffeeList.route)
} else {
password = ""
login = "Неверный логин или пароль"
}
}
},
shape = CircleShape,
modifier = Modifier.fillMaxWidth(fraction = 0.75f),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.primary
)
) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(text = "Войти")
}
Button(
onClick = { navController?.navigate(Screen.Register.route) },
shape = CircleShape,
modifier = Modifier.fillMaxWidth(fraction = 0.75f),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.secondary
)
) {
// Inner content including an icon and a text label
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(text = "Зарегистрироваться")
}
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun LoginPreview() {
CoffeePreorderTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
Login(null)
}
}
}

View File

@ -0,0 +1,31 @@
package com.zyzf.coffeepreorder.database
import android.content.Context
import com.zyzf.coffeepreorder.database.repository.CartRepository
import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineCartRepository
import com.zyzf.coffeepreorder.database.repository.OfflineCoffeeRepository
import com.zyzf.coffeepreorder.database.repository.OfflineUserRepository
import com.zyzf.coffeepreorder.database.repository.UserRepository
interface AppContainer {
val coffeeRepository: CoffeeRepository
val userRepository: UserRepository
val cartRepository: CartRepository
}
class AppDataContainer(private val context: Context) : AppContainer {
override val coffeeRepository: CoffeeRepository by lazy {
OfflineCoffeeRepository(AppDatabase.getInstance(context).coffeeDao())
}
override val userRepository: UserRepository by lazy {
OfflineUserRepository(AppDatabase.getInstance(context).userDao())
}
override val cartRepository: CartRepository by lazy {
OfflineCartRepository(AppDatabase.getInstance(context).cartDao())
}
companion object {
const val TIMEOUT = 5000L
}
}

View File

@ -32,7 +32,7 @@ abstract class AppDatabase : RoomDatabase() {
INSTANCE?.let { database ->
// Users
val userDao = database.userDao()
val user1 = User("zyzf", "Ян К.", "+79911152503", "250303zyzf")
val user1 = User("zyzf", "Ян К.", "+79911152503", "250303zyzf", "admin")
userDao.insert(user1)
// Coffees
val coffeeDao = database.coffeeDao()

View File

@ -3,7 +3,6 @@ package com.zyzf.coffeepreorder.database.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Query
import androidx.room.Update
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
import kotlinx.coroutines.flow.Flow
@ -20,13 +19,13 @@ interface CoffeeDao {
fun getSumInCart(): Double
@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?
@Query("insert into coffee (name, cost, ingredients, count) values (:name, :cost, :ingredients, 0)")
suspend fun insert(name: String, cost: Double, ingredients: String): Long
@Update
suspend fun update(coffee: Coffee)
@Query("update coffee set name = :name, cost = :cost, ingredients = :ingredients, cart_id = :cartId, count = :count where uid = :uid")
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int?
@Delete
suspend fun delete(coffee: Coffee)

View File

@ -12,16 +12,17 @@ interface UserDao {
fun getAll(): Flow<List<User>>
@Query("select * from user where login = :login and password = :password")
suspend fun tryLogin(login: String, password: String): User
suspend fun tryLogin(login: String, password: String): User?
@Query("select * from user where uid = :uid")
suspend fun getByUid(uid: Int): User
suspend fun getByUid(uid: Int): User?
@Query("select user.uid, login, fio, phone, password from user join user_logined on user_logined.user_id = user.uid limit 1")
suspend fun getLogined(): User
@Query("select user.uid, login, fio, phone, password, role from user join user_logined on user_logined.user_id = user.uid limit 1")
suspend fun getLogined(): User?
@Query("insert into user_logined (user_id) values (:userId)")
suspend fun setLogined(userId: Int)
@Query("delete from user_logined")
suspend fun logout()
@ -29,7 +30,7 @@ interface UserDao {
suspend fun insert(user: User)
@Query("update user set login = :login, fio = :fio, phone = :phone, password = :password where uid = :uid")
suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String) : Int
suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String) : Int?
@Query("delete from user where uid = :uid")
suspend fun delete(uid: Int)

View File

@ -38,12 +38,24 @@ data class Coffee(
count: Int?
) : this(null, name, cost, ingredients, null, 0)
companion object {
fun getCoffee(index: Int = 0): Coffee {
return Coffee(
index,
"",
0.0,
"",
null,
0
)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Coffee
if (uid != other.uid) return false
return true
return uid == other.uid
}
override fun hashCode(): Int {

View File

@ -16,22 +16,24 @@ data class User(
@ColumnInfo(name = "phone")
var phone: String,
@ColumnInfo(name = "password")
var password: String
var password: String,
@ColumnInfo(name = "role")
var role: String
) {
@Ignore
constructor(
login: String,
fio: String,
phone: String,
password: String
) : this(null, login, fio, phone, password)
password: String,
role: String
) : this(null, login, fio, phone, password, role)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as User
if (uid != other.uid) return false
return true
return uid == other.uid
}
override fun hashCode(): Int {

View File

@ -0,0 +1,12 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.model.Cart
interface CartRepository {
suspend fun get(): Cart
suspend fun insert(cart: Cart)
suspend fun insertCoffee(cartId: Int, coffeeId: Int, count: Int)
suspend fun deleteCoffee(coffeeId: Int, count: Int)
suspend fun update(cart: Cart)
suspend fun deleteAll()
}

View File

@ -0,0 +1,15 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
import kotlinx.coroutines.flow.Flow
interface CoffeeRepository {
fun getAll(): Flow<List<Coffee>>
fun getAllInCart(): Flow<List<Coffee>>
fun getSumInCart(): Double
suspend fun getByUid(uid: Int): CoffeeWithCart?
suspend fun insert(name: String, cost: Double, ingredients: String): Long
suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int?
suspend fun delete(coffee: Coffee)
}

View File

@ -0,0 +1,13 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.dao.CartDao
import com.zyzf.coffeepreorder.database.model.Cart
class OfflineCartRepository(private val cartDao: CartDao) : CartRepository {
override suspend fun get(): Cart = cartDao.get()
override suspend fun insert(cart: Cart) = cartDao.insert(cart)
override suspend fun insertCoffee(cartId: Int, coffeeId: Int, count: Int) = cartDao.insertCoffee(cartId, coffeeId, count)
override suspend fun deleteCoffee(coffeeId: Int, count: Int) = cartDao.deleteCoffee(coffeeId, count)
override suspend fun update(cart: Cart) = cartDao.update(cart)
override suspend fun deleteAll() = cartDao.deleteAll()
}

View File

@ -0,0 +1,16 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.dao.CoffeeDao
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.model.CoffeeWithCart
import kotlinx.coroutines.flow.Flow
class OfflineCoffeeRepository(private val coffeeDao: CoffeeDao) : CoffeeRepository {
override fun getAll(): Flow<List<Coffee>> = coffeeDao.getAll()
override fun getAllInCart(): Flow<List<Coffee>> = coffeeDao.getAllInCart()
override fun getSumInCart(): Double = coffeeDao.getSumInCart()
override suspend fun getByUid(uid: Int): CoffeeWithCart? = coffeeDao.getByUid(uid)
override suspend fun insert(name: String, cost: Double, ingredients: String): Long = coffeeDao.insert(name, cost, ingredients)
override suspend fun update(uid: Int, name: String, cost: Double, ingredients: String, cartId: Int?, count: Int): Int? = coffeeDao.update(uid, name, cost, ingredients, cartId, count)
override suspend fun delete(coffee: Coffee) = coffeeDao.delete(coffee)
}

View File

@ -0,0 +1,17 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.dao.UserDao
import com.zyzf.coffeepreorder.database.model.User
import kotlinx.coroutines.flow.Flow
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
override fun getAll(): Flow<List<User>> = userDao.getAll()
override suspend fun tryLogin(login: String, password: String): User? = userDao.tryLogin(login, password)
override suspend fun getByUid(uid: Int): User? = userDao.getByUid(uid)
override suspend fun getLogined(): User? = userDao.getLogined()
override suspend fun setLogined(userId: Int) = userDao.setLogined(userId)
override suspend fun logout() = userDao.logout()
override suspend fun insert(user: User) = userDao.insert(user)
override suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String) : Int? = userDao.update(uid, login, fio, phone, password)
override suspend fun delete(uid: Int) = userDao.delete(uid)
}

View File

@ -0,0 +1,16 @@
package com.zyzf.coffeepreorder.database.repository
import com.zyzf.coffeepreorder.database.model.User
import kotlinx.coroutines.flow.Flow
interface UserRepository {
fun getAll(): Flow<List<User>>
suspend fun tryLogin(login: String, password: String): User?
suspend fun getByUid(uid: Int): User?
suspend fun getLogined(): User?
suspend fun setLogined(userId: Int)
suspend fun logout()
suspend fun insert(user: User)
suspend fun update(uid: Int, login: String, fio: String, phone: String, password: String) : Int?
suspend fun delete(uid: Int)
}

View File

@ -0,0 +1,23 @@
package com.zyzf.coffeepreorder.ui
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import com.zyzf.coffeepreorder.CoffeeApplication
import com.zyzf.coffeepreorder.ui.coffee.CoffeeListViewModel
import com.zyzf.coffeepreorder.ui.login.LoginViewModel
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
CoffeeListViewModel(coffeeApplication().container.coffeeRepository, coffeeApplication().container.cartRepository)
}
initializer {
LoginViewModel(coffeeApplication().container.userRepository)
}
}
}
fun CreationExtras.coffeeApplication(): CoffeeApplication =
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as CoffeeApplication)

View File

@ -1,4 +1,4 @@
package com.zyzf.coffeepreorder.composeui
package com.zyzf.coffeepreorder.ui.cart
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
@ -21,7 +21,6 @@ import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@ -48,9 +47,9 @@ import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.composeui.navigation.Screen
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.ui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
@ -58,7 +57,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class, DelicateCoroutinesApi::class)
@OptIn(DelicateCoroutinesApi::class)
@Composable
fun Cart(navController: NavController?) {
val openDialog = remember { mutableStateOf(false) }

View File

@ -0,0 +1,362 @@
package com.zyzf.coffeepreorder.ui.coffee
import android.content.Context
import android.content.res.Configuration
import android.net.Uri
import android.util.Log
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.outlined.Create
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SheetState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CoffeeList(
viewModel: CoffeeListViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val coroutineScope = rememberCoroutineScope()
val coffeeListUiState = viewModel.coffeeListUiState.collectAsState()
val sheetState = rememberModalBottomSheetState()
val openDialog = remember { mutableStateOf(false) }
val photoPicker = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia()
) {
if (it != null) {
Log.d("PhotoPicker", "Selected URI: $it")
viewModel.imageUri = it
} else {
Log.d("PhotoPicker", "No media selected")
}
}
Scaffold(
topBar = {},
floatingActionButton = {
FloatingActionButton(
onClick = {
coroutineScope.launch {
viewModel.cleanCurrentCoffee()
}
},
Modifier
.padding(all = 20.dp)
) {
Icon(
imageVector = Icons.Filled.Add,
contentDescription = "Add",
modifier = Modifier.size(20.dp)
)
}
}
) { innerPadding ->
coffeeListUiState?.value?.coffeeList?.let {
CoffeeList(
modifier = Modifier
.padding(innerPadding)
.fillMaxSize(),
coffeeList = it,
onAddToCartClick = { coffeeUid: Int ->
coroutineScope.launch {
viewModel.addCoffeeToCart(coffeeUid = coffeeUid)
}
},
onEditClick = { coffee: Coffee ->
coroutineScope.launch {
viewModel.editCoffee(coffee = coffee)
}
}
)
}
AddEditModalBottomSheet(
coffee = viewModel.currentCoffee,
sheetState = sheetState,
openDialog = openDialog,
onAddClick = { coffee: Coffee, context: Context ->
coroutineScope.launch {
viewModel.createCoffee(coffee, context)
}
},
onEditClick = { coffee: Coffee, context: Context ->
coroutineScope.launch {
viewModel.editCoffee(coffee, context)
}
},
onDeleteClick = { coffee: Coffee ->
coroutineScope.launch {
viewModel.deleteCoffee(coffee)
}
},
photoPicker = photoPicker,
imageUri = viewModel.imageUri
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun AddEditModalBottomSheet(
coffee: Coffee,
sheetState: SheetState,
openDialog: MutableState<Boolean>,
onAddClick: (coffee: Coffee, context: Context) -> Unit,
onEditClick: (coffee: Coffee, context: Context) -> Unit,
onDeleteClick: (coffee: Coffee) -> Unit,
photoPicker: ManagedActivityResultLauncher<PickVisualMediaRequest, Uri?>,
imageUri: Any?,
modifier: Modifier = Modifier
) {
var name by remember { mutableStateOf(coffee.name) }
var cost by remember { mutableDoubleStateOf(coffee.cost) }
var ingredients by remember { mutableStateOf(coffee.ingredients) }
val context = LocalContext.current
if (openDialog.value) {
ModalBottomSheet(
onDismissRequest = { openDialog.value = false },
sheetState = sheetState
) {
Column(modifier = Modifier
.fillMaxWidth()
.padding(all = 10.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = name, onValueChange = {name = it},
label = {
Text(stringResource(id = R.string.coffee_name))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
)
OutlinedTextField(modifier = Modifier.fillMaxWidth(),
value = cost.toString(), onValueChange = {cost = it.toDouble()},
label = {
Text(stringResource(id = R.string.coffee_cost))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal)
)
OutlinedTextField(modifier = Modifier
.fillMaxWidth()
.padding(bottom = 10.dp),
value = ingredients, onValueChange = {ingredients = it},
label = {
Text(stringResource(id = R.string.coffee_ingredients))
},
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.name != "") "https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.uid +".png" else imageUri)
.crossfade(enable = true)
.build(),
)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
if (coffee.uid == 0) {
Button(onClick = {
onAddClick(coffee, context)
openDialog.value = false
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Добавить")
}
} else {
Button(onClick = {
onEditClick(coffee, context)
openDialog.value = false
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Изменить")
}
Spacer(modifier = Modifier.padding(all = 20.dp))
Button(onClick = {
onDeleteClick(coffee)
openDialog.value = false
}, modifier = Modifier.padding(0.dp, 10.dp, 0.dp, 30.dp)) {
Text("Удалить")
}
}
}
}
}
}
}
@Composable
private fun CoffeeList(
modifier: Modifier = Modifier,
coffeeList: List<Coffee>,
onAddToCartClick: (coffeeUid: Int) -> Unit,
onEditClick: (coffee: Coffee) -> Unit
) {
LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally) {
items(items = coffeeList, key = { it.uid!! }) { coffee ->
CoffeeListItem(coffee = coffee, onAddToCartClick = onAddToCartClick, onEditClick = onEditClick)
}
}
}
@Composable
private fun CoffeeListItem(
coffee: Coffee,
modifier: Modifier = Modifier,
onAddToCartClick: (coffeeUid: Int) -> Unit,
onEditClick: (coffee: Coffee) -> Unit
) {
Row(modifier = Modifier
.fillMaxWidth()
.heightIn(max = 140.dp)
.padding(bottom = 10.dp, top = 10.dp),
horizontalArrangement = Arrangement.SpaceAround) {
AsyncImage(
model = ImageRequest.Builder(context = LocalContext.current).data("https://zyzf.space/s/zXgFRTmbR4KMxMH/download?path=&files=coffee_image_" + coffee.uid +".png")
.crossfade(true).build(),
error = painterResource(R.drawable.ic_broken_image),
placeholder = painterResource(R.drawable.loading_img),
contentDescription = "Кофе",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(100.dp)
.clip(RoundedCornerShape(50.dp))
)
Column(
Modifier
.weight(2f)
.padding(start = 20.dp)) {
Text(text = coffee.name, fontSize = 25.sp)
Text(text = String.format("%.2f", coffee.cost), fontSize = 20.sp)
Text(text = coffee.ingredients, fontSize = 15.sp)
Row(
Modifier
.fillMaxWidth()
.padding(top = 5.dp)) {
Button(
onClick = {
coffee.uid?.let { onAddToCartClick(it) }
},
shape = CircleShape,
modifier = Modifier.fillMaxWidth(fraction = 0.75f)
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(text = "В корзину")
}
OutlinedIconButton(
onClick = {
onEditClick(coffee)
},
Modifier
.padding(start = 10.dp)
.clip(CircleShape)) {
Icon(
imageVector = Icons.Outlined.Create,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
}
}
}
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun CoffeeListPreview() {
CoffeePreorderTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
CoffeeList(
coffeeList = (1..20).map { i -> Coffee.getCoffee(i) },
onAddToCartClick = {},
onEditClick = {}
)
}
}
}

View File

@ -0,0 +1,141 @@
package com.zyzf.coffeepreorder.ui.coffee
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.StrictMode
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
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.database.AppDataContainer
import com.zyzf.coffeepreorder.database.model.Cart
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.database.repository.CartRepository
import com.zyzf.coffeepreorder.database.repository.CoffeeRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.Properties
class CoffeeListViewModel(
private val coffeeRepository: CoffeeRepository,
private val cartRepository: CartRepository
) : ViewModel() {
val coffeeListUiState: StateFlow<CoffeeListUiState> = coffeeRepository.getAll().map {
CoffeeListUiState(it)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
initialValue = CoffeeListUiState()
)
var currentCoffee: Coffee = Coffee.getCoffee()
var imageUri: Any? = R.drawable.img
suspend fun addCoffeeToCart(coffeeUid: Int) {
val cart: Cart = cartRepository.get()
cart.uid?.let { cartRepository.insertCoffee(it, coffeeUid, 1) }
}
fun cleanCurrentCoffee() {
currentCoffee = Coffee.getCoffee()
}
fun editCoffee(coffee: Coffee) {
currentCoffee = coffee
}
suspend fun createCoffee(coffee: Coffee, context: Context) {
val newCoffee: Long = coffeeRepository.insert(coffee.name, coffee.cost, coffee.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(Bitmap.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")
}
suspend fun editCoffee(coffee: Coffee, context: Context) {
val editedCoffee: Int = coffeeRepository.update(coffee.uid!!, coffee.name, coffee.cost, coffee.ingredients, coffee.cartId, coffee.count)!!
val inputStream = context.contentResolver.openInputStream(imageUri as Uri)
val bitmap = BitmapFactory.decodeStream(inputStream)
val f = File(context.cacheDir, "coffee_image_$editedCoffee.png")
withContext(Dispatchers.IO) {
f.createNewFile()
val bos = ByteArrayOutputStream()
bitmap.compress(Bitmap.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")
}
suspend fun deleteCoffee(coffee: Coffee) {
coffeeRepository.delete(coffee)
}
}
data class CoffeeListUiState(val coffeeList: List<Coffee> = listOf())
const val REMOTE_HOST = "109.197.199.134"
const val USERNAME = "zyzf"
const val PASSWORD = "250303Zyzf-d-grad"
const val REMOTE_PORT = 2223
fun copyFileToSftp(srcFile: File, ftpPath: String): Boolean {
var jschSession: Session? = null
try {
val jsch = JSch()
jsch.setKnownHosts("/home/zyzf/.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 = StrictMode.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
}

View File

@ -0,0 +1,153 @@
package com.zyzf.coffeepreorder.ui.login
import android.annotation.SuppressLint
import android.content.res.Configuration
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.ui.AppViewModelProvider
import com.zyzf.coffeepreorder.ui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.launch
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun Login(
navController: NavController?,
viewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
val coroutineScope = rememberCoroutineScope()
val userListUiState = viewModel.userListUiState.collectAsState()
var login by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
Scaffold(
topBar = {},
floatingActionButton = {}
) {
Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) {
AsyncImage(
model = ImageRequest.Builder(context = LocalContext.current)
.data("https://zyzf.space/s/YsHjPo3NDmoptSk/download/coffee_image.png")
.crossfade(true).build(),
error = painterResource(R.drawable.ic_broken_image),
placeholder = painterResource(R.drawable.loading_img),
contentDescription = "Кофе",
contentScale = ContentScale.Crop,
modifier = Modifier.size(150.dp)
)
Spacer(modifier = Modifier.padding(all = 20.dp))
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = login, onValueChange = { login = it },
label = {
Text(stringResource(id = R.string.profile_login_label))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = password, onValueChange = { password = it },
label = {
Text(stringResource(id = R.string.profile_passw_label))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
visualTransformation = PasswordVisualTransformation()
)
Spacer(modifier = Modifier.padding(all = 20.dp))
Button(
onClick = {
coroutineScope.launch {
if (viewModel.tryLogin(login, password)) {
navController?.navigate(Screen.CoffeeList.route)
} else {
password = ""
login = "Неверный логин или пароль"
}
}
},
shape = CircleShape,
modifier = Modifier.fillMaxWidth(fraction = 0.75f),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.primary
)
) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(text = "Войти")
}
Button(
onClick = { navController?.navigate(Screen.Register.route) },
shape = CircleShape,
modifier = Modifier.fillMaxWidth(fraction = 0.75f),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.secondary
)
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = "Favorite",
modifier = Modifier.size(20.dp)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(text = "Зарегистрироваться")
}
}
}
}
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun LoginPreview() {
CoffeePreorderTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
Login(null)
}
}
}

View File

@ -0,0 +1,36 @@
package com.zyzf.coffeepreorder.ui.login
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zyzf.coffeepreorder.database.AppDataContainer
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.database.repository.UserRepository
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
class LoginViewModel(
private val userRepository: UserRepository
) : ViewModel() {
val userListUiState: StateFlow<UserListUiState> = userRepository.getAll().map {
UserListUiState(it)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
initialValue = UserListUiState()
)
var user: User? = null
suspend fun tryLogin(login: String, password: String): Boolean {
user = userRepository.tryLogin(login, password)
return if (user != null) {
userRepository.logout()
userRepository.setLogined(user!!.uid!!)
true
} else {
false
}
}
}
data class UserListUiState(val userList: List<User> = listOf())

View File

@ -1,10 +1,10 @@
package com.zyzf.coffeepreorder.composeui.navigation
package com.zyzf.coffeepreorder.ui.navigation
import android.content.res.Configuration
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@ -25,20 +25,17 @@ import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.coffee.composeui.CoffeeList
import com.zyzf.coffeepreorder.coffee.composeui.CoffeeView
import com.zyzf.coffeepreorder.composeui.Cart
import com.zyzf.coffeepreorder.composeui.Login
import com.zyzf.coffeepreorder.composeui.Order
import com.zyzf.coffeepreorder.composeui.Profile
import com.zyzf.coffeepreorder.composeui.Register
import com.zyzf.coffeepreorder.ui.cart.Cart
import com.zyzf.coffeepreorder.ui.coffee.CoffeeList
import com.zyzf.coffeepreorder.ui.login.Login
import com.zyzf.coffeepreorder.ui.order.Order
import com.zyzf.coffeepreorder.ui.profile.Profile
import com.zyzf.coffeepreorder.ui.register.Register
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
@OptIn(ExperimentalMaterial3Api::class)
@ -62,7 +59,7 @@ fun Topbar(
) {
IconButton(onClick = { navController.navigateUp() }) {
Icon(
imageVector = Icons.Filled.ArrowBack,
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = null,
tint = MaterialTheme.colorScheme.onPrimary
)
@ -111,16 +108,10 @@ fun Navhost(
) {
composable(Screen.Login.route) { Login(navController) }
composable(Screen.Register.route) { Register(navController) }
composable(Screen.CoffeeList.route) { CoffeeList(navController) }
composable(Screen.CoffeeList.route) { CoffeeList() }
composable(Screen.Profile.route) { Profile(navController) }
composable(Screen.Cart.route) { Cart(navController) }
composable(Screen.Order.route) { Order(navController) }
composable(
Screen.CoffeeView.route,
arguments = listOf(navArgument("id") { type = NavType.IntType })
) { backStackEntry ->
backStackEntry.arguments?.let { CoffeeView(navController, it.getInt("id")) }
}
}
}

View File

@ -1,4 +1,4 @@
package com.zyzf.coffeepreorder.composeui.navigation
package com.zyzf.coffeepreorder.ui.navigation
import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
@ -46,7 +46,7 @@ enum class Screen(
fun getItem(route: String): Screen? {
val findRoute = route.split("/").first()
return values().find { value -> value.route.startsWith(findRoute) }
return entries.find { value -> value.route.startsWith(findRoute) }
}
}
}

View File

@ -1,4 +1,4 @@
package com.zyzf.coffeepreorder.composeui
package com.zyzf.coffeepreorder.ui.order
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
@ -41,8 +41,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.navigation.NavController
import com.zyzf.coffeepreorder.composeui.navigation.Screen
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.ui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

View File

@ -1,4 +1,4 @@
package com.zyzf.coffeepreorder.composeui
package com.zyzf.coffeepreorder.ui.profile
import android.content.res.Configuration
import androidx.compose.foundation.BorderStroke
@ -41,9 +41,9 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.composeui.navigation.Screen
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.ui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
@ -58,7 +58,7 @@ fun Profile(navController: NavController?) {
val openDialogExit = remember { mutableStateOf(false) }
val openDialogDelete = remember { mutableStateOf(false) }
val context = LocalContext.current
var user: User by remember { mutableStateOf(User("", "", "", "")) }
var user: User by remember { mutableStateOf(User("", "", "", "", "")) }
var userLogin by remember { mutableStateOf("") }
var userFIO by remember { mutableStateOf("") }
var userPhone by remember { mutableStateOf("") }
@ -67,7 +67,7 @@ fun Profile(navController: NavController?) {
val userNewPsswdConf = remember { mutableStateOf("") }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
user = AppDatabase.getInstance(context).userDao().getLogined()
user = AppDatabase.getInstance(context).userDao().getLogined()!!
userLogin = user.login
userFIO = user.fio
userPhone = user.phone
@ -195,7 +195,7 @@ fun Profile(navController: NavController?) {
GlobalScope.launch (Dispatchers.Main) {
if (userOldPsswd.value == user.password && userNewPsswd.value == userNewPsswdConf.value) {
AppDatabase.getInstance(context).userDao().update(user.uid!!, userLogin, userFIO, userPhone, userNewPsswd.value)
user = AppDatabase.getInstance(context).userDao().getLogined()
user = AppDatabase.getInstance(context).userDao().getLogined()!!
}
}
openDialogEdit.value = false

View File

@ -1,4 +1,4 @@
package com.zyzf.coffeepreorder.composeui
package com.zyzf.coffeepreorder.ui.register
import android.content.res.Configuration
@ -37,9 +37,9 @@ import androidx.navigation.NavController
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.composeui.navigation.Screen
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.User
import com.zyzf.coffeepreorder.ui.navigation.Screen
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
@ -106,7 +106,7 @@ fun Register(navController: NavController?) {
var user: User?
GlobalScope.launch (Dispatchers.Main) {
if (password == confPassword) {
AppDatabase.getInstance(context).userDao().insert(User(login, fio, phone, password))
AppDatabase.getInstance(context).userDao().insert(User(login, fio, phone, password, "user"))
user = AppDatabase.getInstance(context).userDao().tryLogin(login, password)
if (user != null) {
AppDatabase.getInstance(context).userDao().logout()

View File

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.4" 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.android.application") version "8.2.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
id("com.google.devtools.ksp") version "1.9.20-1.0.14" apply false
}

View File

@ -1,6 +1,6 @@
#Sun Oct 15 15:51:04 GMT+04:00 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists