From 7472b31ba2fc8da1f0f499d6a2aea409727cb6e8 Mon Sep 17 00:00:00 2001 From: Zyzf Date: Sat, 28 Oct 2023 23:22:11 +0400 Subject: [PATCH] some done.. --- .idea/misc.xml | 1 + app/build.gradle.kts | 35 +++-- app/src/main/AndroidManifest.xml | 2 + .../coffee/composeui/CoffeeList.kt | 134 +++++++++++++++--- .../zyzf/coffeepreorder/composeui/Login.kt | 65 +++++++-- .../zyzf/coffeepreorder/composeui/Profile.kt | 54 +++++-- .../composeui/navigation/MainNavbar.kt | 2 +- .../composeui/navigation/Screen.kt | 4 +- .../coffeepreorder/database/AppDatabase.kt | 88 ++++++++++++ .../coffeepreorder/database/dao/CartDao.kt | 28 ++++ .../coffeepreorder/database/dao/CoffeeDao.kt | 28 ++++ .../coffeepreorder/database/dao/UserDao.kt | 38 +++++ .../coffeepreorder/database/model/Cart.kt | 26 ++++ .../coffeepreorder/database/model/Coffee.kt | 52 +++++++ .../database/model/CoffeeWithCart.kt | 11 ++ .../coffeepreorder/database/model/User.kt | 40 ++++++ .../database/model/UserLogined.kt | 40 ++++++ app/src/main/res/drawable/ic_broken_image.xml | 25 ++++ .../main/res/drawable/ic_connection_error.xml | 25 ++++ app/src/main/res/drawable/loading_img.xml | 94 ++++++++++++ build.gradle.kts | 1 + 21 files changed, 735 insertions(+), 58 deletions(-) create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/AppDatabase.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/dao/CartDao.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/dao/CoffeeDao.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/dao/UserDao.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/model/Cart.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/model/Coffee.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/model/CoffeeWithCart.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/model/User.kt create mode 100644 app/src/main/java/com/zyzf/coffeepreorder/database/model/UserLogined.kt create mode 100644 app/src/main/res/drawable/ic_broken_image.xml create mode 100644 app/src/main/res/drawable/ic_connection_error.xml create mode 100644 app/src/main/res/drawable/loading_img.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..0ad17cb 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index de6c85f..7d5eea7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("com.google.devtools.ksp") } android { @@ -30,17 +31,17 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "11" + jvmTarget = "17" } buildFeatures { compose = true } composeOptions { - kotlinCompilerExtensionVersion = "1.4.5" + kotlinCompilerExtensionVersion = "1.5.3" } packaging { resources { @@ -49,23 +50,41 @@ android { } } -dependencies { - val composeBom = platform("androidx.compose:compose-bom:2023.10.00") - implementation("androidx.compose:compose-bom:2023.10.01") - androidTestImplementation("androidx.compose:compose-bom:2023.10.01") +kotlin { + jvmToolchain(17) +} +dependencies { + // Core implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") + + // UI implementation("androidx.activity:activity-compose:1.8.0") + implementation(platform("androidx.compose:compose-bom:2023.10.01")) implementation("androidx.navigation:navigation-compose:2.7.4") implementation("androidx.compose.ui:ui:1.6.0-alpha08") implementation("androidx.compose.ui:ui-graphics:1.6.0-alpha08") implementation("androidx.compose.ui:ui-tooling-preview:1.6.0-alpha08") implementation("androidx.compose.material3:material3:1.2.0-alpha10") + + implementation("io.coil-kt:coil-compose:2.4.0") + + // 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") + + // 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-alpha08") debugImplementation("androidx.compose.ui:ui-tooling:1.6.0-alpha08") debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.0-alpha08") + + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1464c10..78fcc00 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + () } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + AppDatabase.getInstance(context).coffeeDao().getAll().collect { data -> + itemsList.clear() + itemsList.addAll(data) + } + } + } LazyColumn( horizontalAlignment = Alignment.CenterHorizontally) { items(itemsList) { currentCoffee -> @@ -63,10 +88,17 @@ fun CoffeeList(navController: NavController?) { .heightIn(max = 140.dp) .padding(bottom = 10.dp, top = 10.dp), horizontalArrangement = Arrangement.SpaceAround) { - Image(bitmap = ImageBitmap.imageResource(currentCoffee.image), - contentDescription = "Кофе", modifier = Modifier - .fillMaxHeight() - .weight(1f)) + + 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") + .crossfade(true).build(), + error = painterResource(R.drawable.ic_broken_image), + placeholder = painterResource(R.drawable.loading_img), + contentDescription = "Кофе", + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxHeight().weight(1f) + ) + Column( Modifier .weight(2f) @@ -79,7 +111,19 @@ fun CoffeeList(navController: NavController?) { .fillMaxWidth() .padding(top = 5.dp)) { Button( - onClick = { /* ... */ }, + onClick = { + GlobalScope.launch (Dispatchers.Main) { + currentCoffee.uid?.let { + AppDatabase.getInstance(context).cartDao().get().uid?.let { it1 -> + AppDatabase.getInstance(context).cartDao().insertCoffee( + it1, + it, + 1 + ) + } + } + } + }, shape = CircleShape, modifier = Modifier.fillMaxWidth(fraction = 0.75f) ) { @@ -108,7 +152,7 @@ fun CoffeeList(navController: NavController?) { } } Box(modifier = Modifier.fillMaxSize()) { - FloatingActionButton(onClick = { coffee.value = Coffee("", 0.0, "", 1) ; add.value = true; openDialog.value = true }, + FloatingActionButton(onClick = { coffee.value = Coffee("", 0.0, "", null, 0); add.value = true; openDialog.value = true }, Modifier .padding(all = 20.dp) .align(alignment = Alignment.BottomEnd)) { @@ -120,37 +164,81 @@ fun CoffeeList(navController: NavController?) { } } 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 = coffee.value.name, onValueChange = {}, readOnly = true, + value = name, onValueChange = {name = it}, label = { Text(stringResource(id = R.string.coffee_name)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = coffee.value.cost.toString(), onValueChange = {}, readOnly = true, + value = cost.toString(), onValueChange = {cost = it.toDouble()}, label = { Text(stringResource(id = R.string.coffee_cost)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal) ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = coffee.value.ingredients, onValueChange = {}, readOnly = true, + value = ingredients, onValueChange = {ingredients = it}, label = { Text(stringResource(id = R.string.coffee_ingredients)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) ) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { - Button(onClick = { }) { - if (add.value) { + if (add.value) { + Button(onClick = { + GlobalScope.launch (Dispatchers.Main) { + AppDatabase.getInstance(context).coffeeDao().insert( + Coffee(name = name, cost = cost, ingredients = ingredients, cartId = null, 0) + ) + AppDatabase.getInstance(context).coffeeDao().getAll().collect { data -> + itemsList.clear() + itemsList.addAll(data) + } + } + }) { Text("Добавить") - }else { + } + } 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) + } + } + + }) { 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) + } + } + }) { + Text("Удалить") + } } } } diff --git a/app/src/main/java/com/zyzf/coffeepreorder/composeui/Login.kt b/app/src/main/java/com/zyzf/coffeepreorder/composeui/Login.kt index 7d20c7b..6d05c4d 100644 --- a/app/src/main/java/com/zyzf/coffeepreorder/composeui/Login.kt +++ b/app/src/main/java/com/zyzf/coffeepreorder/composeui/Login.kt @@ -1,13 +1,13 @@ package com.zyzf.coffeepreorder.composeui import android.content.res.Configuration -import androidx.compose.foundation.Image 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 @@ -19,41 +19,86 @@ 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.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext @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) { - Image( - painter = painterResource(id = R.drawable.coffee_image), - contentDescription = "Logo", - modifier = Modifier.size(150.dp) + AsyncImage( + model = ImageRequest.Builder(context = LocalContext.current).data("http://109.197.199.134/s/zXgFRTmbR4KMxMH/download?path=%2F&files=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 ) Spacer(modifier = Modifier.padding(all = 20.dp)) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "", onValueChange = {}, readOnly = true, + value = login, onValueChange = {login = it}, label = { Text(stringResource(id = R.string.profile_login_label)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "", onValueChange = {}, readOnly = true, + 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 = { navController?.navigate(Screen.CoffeeList.route) }, + onClick = { + var user: User? + GlobalScope.launch (Dispatchers.Main) { + user = AppDatabase.getInstance(context).userDao().tryLogin(login, password) + if (user != null) { + 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( diff --git a/app/src/main/java/com/zyzf/coffeepreorder/composeui/Profile.kt b/app/src/main/java/com/zyzf/coffeepreorder/composeui/Profile.kt index bd27bb0..0d41438 100644 --- a/app/src/main/java/com/zyzf/coffeepreorder/composeui/Profile.kt +++ b/app/src/main/java/com/zyzf/coffeepreorder/composeui/Profile.kt @@ -8,11 +8,11 @@ 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.Close import androidx.compose.material.icons.filled.Create import androidx.compose.material.icons.filled.Edit -import androidx.compose.material.icons.filled.ExitToApp import androidx.compose.material.icons.outlined.Clear import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button @@ -25,60 +25,86 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext 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 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.Dispatchers +import kotlinx.coroutines.withContext @Composable fun Profile(navController: NavController?) { val openDialogEdit = remember { mutableStateOf(false) } val openDialogExit = remember { mutableStateOf(false) } val openDialogDelete = remember { mutableStateOf(false) } + val context = LocalContext.current + val user = remember { mutableStateOf(User("", "", "", "")) } + val userOldPsswd = remember { mutableStateOf("") } + val userNewPsswd = remember { mutableStateOf("") } + val userNewPsswdConf = remember { mutableStateOf("") } + LaunchedEffect(Unit) { + withContext(Dispatchers.IO) { + user.value = AppDatabase.getInstance(context).userDao().getLogined() + } + } Column(Modifier.padding(all = 10.dp), horizontalAlignment = Alignment.CenterHorizontally) { OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "zyzf", onValueChange = {}, readOnly = true, + value = user.value.login, onValueChange = {user.value.login = it}, label = { Text(stringResource(id = R.string.profile_login_label)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "Калышев Ян", onValueChange = {}, readOnly = true, + value = user.value.fio, onValueChange = {user.value.fio = it}, label = { Text(stringResource(id = R.string.profile_fio_label)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text) ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "+79911152503", onValueChange = {}, readOnly = true, + value = user.value.phone, onValueChange = {user.value.phone = it}, label = { Text(stringResource(id = R.string.profile_phone_label)) } ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "Старый пароль", onValueChange = {}, readOnly = true, + value = userOldPsswd.value, onValueChange = {userOldPsswd.value = it}, label = { Text(stringResource(id = R.string.profile_oldpassw_label)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + visualTransformation = PasswordVisualTransformation() ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "Новый пароль", onValueChange = {}, readOnly = true, + value = userNewPsswd.value, onValueChange = {userNewPsswd.value = it}, label = { Text(stringResource(id = R.string.profile_newpassw_label)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + visualTransformation = PasswordVisualTransformation() ) OutlinedTextField(modifier = Modifier.fillMaxWidth(), - value = "Подтверждение пароля", onValueChange = {}, readOnly = true, + value = userNewPsswdConf.value, onValueChange = {userNewPsswdConf.value = it}, label = { Text(stringResource(id = R.string.profile_confpassw_label)) - } + }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + visualTransformation = PasswordVisualTransformation() ) Spacer(modifier = Modifier.padding(all = 20.dp)) Button( @@ -110,7 +136,7 @@ fun Profile(navController: NavController?) { ) { // Inner content including an icon and a text label Icon( - imageVector = Icons.Default.ExitToApp, + imageVector = Icons.Default.Close, contentDescription = "Favorite", modifier = Modifier.size(20.dp) ) @@ -175,7 +201,7 @@ fun Profile(navController: NavController?) { if (openDialogExit.value) { AlertDialog( icon = { - Icon(Icons.Default.ExitToApp, contentDescription = "Example Icon") + Icon(Icons.Default.Close, contentDescription = "Example Icon") }, title = { Text(text = "Подтверждение") diff --git a/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/MainNavbar.kt b/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/MainNavbar.kt index 206f194..44f8b5c 100644 --- a/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/MainNavbar.kt +++ b/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/MainNavbar.kt @@ -48,7 +48,7 @@ fun Topbar( currentScreen: Screen? ) { TopAppBar( - colors = TopAppBarDefaults.smallTopAppBarColors( + colors = TopAppBarDefaults.mediumTopAppBarColors( containerColor = MaterialTheme.colorScheme.primary, titleContentColor = MaterialTheme.colorScheme.onPrimary, ), diff --git a/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/Screen.kt b/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/Screen.kt index 7bac36e..38523b9 100644 --- a/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/Screen.kt +++ b/app/src/main/java/com/zyzf/coffeepreorder/composeui/navigation/Screen.kt @@ -4,7 +4,7 @@ import androidx.annotation.StringRes import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.material.icons.filled.Favorite -import androidx.compose.material.icons.filled.List +import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.ShoppingCart import androidx.compose.ui.graphics.vector.ImageVector import com.zyzf.coffeepreorder.R @@ -22,7 +22,7 @@ enum class Screen( "register", R.string.coffee_register, showInBottomBar = false ), CoffeeList( - "coffee-list", R.string.coffee_main_title, Icons.Filled.List + "coffee-list", R.string.coffee_main_title, Icons.Filled.Menu ), Profile( "profile", R.string.profile_title, Icons.Filled.AccountCircle diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/AppDatabase.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/AppDatabase.kt new file mode 100644 index 0000000..5c6094d --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/AppDatabase.kt @@ -0,0 +1,88 @@ +package com.zyzf.coffeepreorder.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.sqlite.db.SupportSQLiteDatabase +import com.zyzf.coffeepreorder.database.dao.CartDao +import com.zyzf.coffeepreorder.database.dao.CoffeeDao +import com.zyzf.coffeepreorder.database.dao.UserDao +import com.zyzf.coffeepreorder.database.model.Cart +import com.zyzf.coffeepreorder.database.model.Coffee +import com.zyzf.coffeepreorder.database.model.User +import com.zyzf.coffeepreorder.database.model.UserLogined +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +@Database(entities = [User::class, Coffee::class, Cart::class, UserLogined::class], version = 1, exportSchema = false) +abstract class AppDatabase : RoomDatabase() { + abstract fun userDao(): UserDao + abstract fun coffeeDao(): CoffeeDao + abstract fun cartDao(): CartDao + + companion object { + private const val DB_NAME: String = "coffee-preorder" + + @Volatile + private var INSTANCE: AppDatabase? = null + + private suspend fun populateDatabase() { + INSTANCE?.let { database -> + // Users + val userDao = database.userDao() + val user1 = User("zyzf", "Ян К.", "+79911152503", "250303zyzf") + userDao.insert(user1) + // Coffees + val coffeeDao = database.coffeeDao() + val coffee1 = Coffee("Coffee1", 200.0, "Ing1", null, 0) + val coffee2 = Coffee("Coffee2", 200.0, "Ing1", null, 0) + val coffee3 = Coffee("Coffee3", 300.0, "Ing1", null, 0) + val coffee4 = Coffee("Coffee4", 200.0, "Ing1", null, 0) + val coffee5 = Coffee("Coffee5", 200.0, "Ing1", null, 0) + val coffee6 = Coffee("Coffee6", 25.0, "Ing1", null, 0) + val coffee7 = Coffee("Coffee7", 400.0, "Ing1", null, 0) + val coffee8 = Coffee("Coffee8", 200.0, "Ing1", null, 0) + val coffee9 = Coffee("Coffee9", 200.0, "Ing1", null, 0) + val coffee10 = Coffee("Coffee10", 900.0, "Ing1", null, 0) + val coffee11 = Coffee("Coffee11", 200.0, "Ing1", null, 0) + coffeeDao.insert(coffee1) + coffeeDao.insert(coffee2) + coffeeDao.insert(coffee3) + coffeeDao.insert(coffee4) + coffeeDao.insert(coffee5) + coffeeDao.insert(coffee6) + coffeeDao.insert(coffee7) + coffeeDao.insert(coffee8) + coffeeDao.insert(coffee9) + coffeeDao.insert(coffee10) + coffeeDao.insert(coffee11) + // Cart + val cartDao = database.cartDao() + val cart = Cart() + cartDao.insert(cart) + } + } + + fun getInstance(appContext: Context): AppDatabase { + return INSTANCE ?: synchronized(this) { + Room.databaseBuilder( + appContext, + AppDatabase::class.java, + DB_NAME + ) + .addCallback(object : Callback() { + override fun onCreate(db: SupportSQLiteDatabase) { + super.onCreate(db) + CoroutineScope(Dispatchers.IO).launch { + populateDatabase() + } + } + }) + .build() + .also { INSTANCE = it } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/dao/CartDao.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/dao/CartDao.kt new file mode 100644 index 0000000..57e1738 --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/dao/CartDao.kt @@ -0,0 +1,28 @@ +package com.zyzf.coffeepreorder.database.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.zyzf.coffeepreorder.database.model.Cart + +@Dao +interface CartDao { + @Query("select * from cart limit 1") + suspend fun get(): Cart + + @Insert + suspend fun insert(cart: Cart) + + @Query("update coffee set cart_id = :cartId, count = count + :count where uid = :coffeeId") + suspend fun insertCoffee(cartId: Int, coffeeId: Int, count: Int) + + @Query("update coffee set count = count - :count where uid = :coffeeId") + suspend fun deleteCoffee(coffeeId: Int, count: Int) + + @Update + suspend fun update(cart: Cart) + + @Query("delete from cart") + suspend fun deleteAll() +} \ No newline at end of file diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/dao/CoffeeDao.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/dao/CoffeeDao.kt new file mode 100644 index 0000000..d739d78 --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/dao/CoffeeDao.kt @@ -0,0 +1,28 @@ +package com.zyzf.coffeepreorder.database.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +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 + +@Dao +interface CoffeeDao { + @Query("select * from coffee order by name collate nocase asc") + fun getAll(): Flow> + + @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 + + @Insert + suspend fun insert(coffee: Coffee) + + @Update + suspend fun update(coffee: Coffee) + + @Delete + suspend fun delete(coffee: Coffee) +} \ No newline at end of file diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/dao/UserDao.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/dao/UserDao.kt new file mode 100644 index 0000000..ad4302b --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/dao/UserDao.kt @@ -0,0 +1,38 @@ +package com.zyzf.coffeepreorder.database.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.zyzf.coffeepreorder.database.model.User +import kotlinx.coroutines.flow.Flow + +@Dao +interface UserDao { + @Query("select * from user") + fun getAll(): Flow> + + @Query("select * from user where login = :login and password = :password") + suspend fun tryLogin(login: String, password: String): User + + @Query("select * from user where uid = :uid") + suspend fun getByUid(uid: Int): User + + @Query("select * from user left 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() + + @Insert + suspend fun insert(user: User) + + @Update + suspend fun update(user: User) + + @Delete + suspend fun delete(user: User) +} \ No newline at end of file diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/model/Cart.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/model/Cart.kt new file mode 100644 index 0000000..56f00a8 --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/model/Cart.kt @@ -0,0 +1,26 @@ +package com.zyzf.coffeepreorder.database.model + +import androidx.room.Entity +import androidx.room.Ignore +import androidx.room.PrimaryKey + +@Entity(tableName = "cart") +data class Cart( + @PrimaryKey(autoGenerate = true) + val uid: Int? +) { + @Ignore + constructor() : this(null) + + 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 + } + + override fun hashCode(): Int { + return uid ?: -1 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/model/Coffee.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/model/Coffee.kt new file mode 100644 index 0000000..72b9029 --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/model/Coffee.kt @@ -0,0 +1,52 @@ +package com.zyzf.coffeepreorder.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Ignore +import androidx.room.PrimaryKey + +@Entity(tableName = "coffee", foreignKeys = [ + ForeignKey( + entity = Cart::class, + parentColumns = ["uid"], + childColumns = ["cart_id"], + onDelete = ForeignKey.RESTRICT, + onUpdate = ForeignKey.RESTRICT + ) +]) +data class Coffee( + @PrimaryKey(autoGenerate = true) + val uid: Int?, + @ColumnInfo(name = "name") + val name: String, + @ColumnInfo(name = "cost") + val cost: Double, + @ColumnInfo(name = "ingredients") + val ingredients: String, + @ColumnInfo(name = "cart_id", index = true) + val cartId: Int?, + @ColumnInfo(name = "count") + val count: Int = 0 +) { + @Ignore + constructor( + name: String, + cost: Double, + ingredients: String, + cartId: Int?, + count: Int? + ) : this(null, name, cost, ingredients, 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 + } + + override fun hashCode(): Int { + return uid ?: -1 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/model/CoffeeWithCart.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/model/CoffeeWithCart.kt new file mode 100644 index 0000000..00171f2 --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/model/CoffeeWithCart.kt @@ -0,0 +1,11 @@ +package com.zyzf.coffeepreorder.database.model + +import androidx.room.ColumnInfo +import androidx.room.Embedded + +data class CoffeeWithCart( + @Embedded + val coffee: Coffee, + @ColumnInfo(name = "cart_uid") + val cartUid: Int +) diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/model/User.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/model/User.kt new file mode 100644 index 0000000..0d57162 --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/model/User.kt @@ -0,0 +1,40 @@ +package com.zyzf.coffeepreorder.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Ignore +import androidx.room.PrimaryKey + +@Entity(tableName = "user") +data class User( + @PrimaryKey(autoGenerate = true) + val uid: Int?, + @ColumnInfo(name = "login") + var login: String, + @ColumnInfo(name = "fio") + var fio: String, + @ColumnInfo(name = "phone") + var phone: String, + @ColumnInfo(name = "password") + var password: String +) { + @Ignore + constructor( + login: String, + fio: String, + phone: String, + password: String + ) : this(null, login, fio, phone, password) + + 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 + } + + override fun hashCode(): Int { + return uid ?: -1 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/zyzf/coffeepreorder/database/model/UserLogined.kt b/app/src/main/java/com/zyzf/coffeepreorder/database/model/UserLogined.kt new file mode 100644 index 0000000..c9bf90b --- /dev/null +++ b/app/src/main/java/com/zyzf/coffeepreorder/database/model/UserLogined.kt @@ -0,0 +1,40 @@ +package com.zyzf.coffeepreorder.database.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Ignore +import androidx.room.PrimaryKey + +@Entity(tableName = "user_logined", foreignKeys = [ + ForeignKey( + entity = User::class, + parentColumns = ["uid"], + childColumns = ["user_id"], + onDelete = ForeignKey.RESTRICT, + onUpdate = ForeignKey.RESTRICT + )] +) +data class UserLogined( + @PrimaryKey(autoGenerate = true) + val uid: Int?, + @ColumnInfo(name = "user_id", index = true) + val userId: Int? +) { + @Ignore + constructor( + userId: Int? + ) : this(null, userId) + + 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 + } + + override fun hashCode(): Int { + return uid ?: -1 + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_broken_image.xml b/app/src/main/res/drawable/ic_broken_image.xml new file mode 100644 index 0000000..c3b995b --- /dev/null +++ b/app/src/main/res/drawable/ic_broken_image.xml @@ -0,0 +1,25 @@ + + + + diff --git a/app/src/main/res/drawable/ic_connection_error.xml b/app/src/main/res/drawable/ic_connection_error.xml new file mode 100644 index 0000000..a961d63 --- /dev/null +++ b/app/src/main/res/drawable/ic_connection_error.xml @@ -0,0 +1,25 @@ + + + + diff --git a/app/src/main/res/drawable/loading_img.xml b/app/src/main/res/drawable/loading_img.xml new file mode 100644 index 0000000..0b64932 --- /dev/null +++ b/app/src/main/res/drawable/loading_img.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + diff --git a/build.gradle.kts b/build.gradle.kts index 914c55c..05aec1c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,4 +2,5 @@ plugins { id("com.android.application") version "8.1.2" 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 } \ No newline at end of file