some done..

This commit is contained in:
Zyzf 2023-10-28 23:22:11 +04:00
parent e8d279bc28
commit 7472b31ba2
21 changed files with 735 additions and 58 deletions

View File

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

View File

@ -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")
}

View File

@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"

View File

@ -1,7 +1,8 @@
package com.zyzf.coffeepreorder.coffee.composeui
import android.annotation.SuppressLint
import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -16,6 +17,7 @@ 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.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.outlined.Create
@ -31,30 +33,53 @@ 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.graphics.ImageBitmap
import androidx.compose.ui.res.imageResource
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.zyzf.coffeepreorder.R
import com.zyzf.coffeepreorder.coffee.model.Coffee
import com.zyzf.coffeepreorder.coffee.model.getCoffee
import com.zyzf.coffeepreorder.database.AppDatabase
import com.zyzf.coffeepreorder.database.model.Coffee
import com.zyzf.coffeepreorder.ui.theme.CoffeePreorderTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun CoffeeList(navController: NavController?) {
val openDialog = remember { mutableStateOf(false) }
val add = remember { mutableStateOf(false) }
val coffee = remember { mutableStateOf(Coffee("", 0.0, "", 1)) }
val itemsList = getCoffee().toList()
val coffee = remember { mutableStateOf(Coffee("", 0.0, "", null,0)) }
val context = LocalContext.current
val itemsList = remember { mutableStateListOf<Coffee>() }
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("Удалить")
}
}
}
}

View File

@ -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(

View File

@ -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>(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 = "Подтверждение")

View File

@ -48,7 +48,7 @@ fun Topbar(
currentScreen: Screen?
) {
TopAppBar(
colors = TopAppBarDefaults.smallTopAppBarColors(
colors = TopAppBarDefaults.mediumTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primary,
titleContentColor = MaterialTheme.colorScheme.onPrimary,
),

View File

@ -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

View File

@ -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 }
}
}
}
}

View File

@ -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()
}

View File

@ -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<List<Coffee>>
@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)
}

View File

@ -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<List<User>>
@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)
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
)

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,25 @@
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#A9A9AC"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M21,5v6.59l-3,-3.01 -4,4.01 -4,-4 -4,4 -3,-3.01L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l3,2.99 4,-4 4,4 4,-3.99z" />
</vector>

View File

@ -0,0 +1,25 @@
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="100dp"
android:height="100dp"
android:tint="#A9A9AC"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#A9A9AC"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4c-1.48,0 -2.85,0.43 -4.01,1.17l1.46,1.46C10.21,6.23 11.08,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,1.13 -0.64,2.11 -1.56,2.62l1.45,1.45C23.16,18.16 24,16.68 24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96zM3,5.27l2.75,2.74C2.56,8.15 0,10.77 0,14c0,3.31 2.69,6 6,6h11.73l2,2L21,20.73 4.27,4 3,5.27zM7.73,10l8,8H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73z" />
</vector>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="72"
android:viewportHeight="72">
<path
android:fillColor="#cccccf"
android:pathData="M36.06,28.92L36.06,32.18"
android:strokeWidth="1"
android:strokeColor="#e7e7e7"
android:strokeLineCap="round" />
<path
android:fillColor="#c8c8cc"
android:pathData="M39.45,29.88L37.82,32.71"
android:strokeWidth="1"
android:strokeColor="#cacaca"
android:strokeLineCap="round" />
<path
android:fillColor="#bbbbbe"
android:pathData="M42.12,32.32L39.3,33.95"
android:strokeWidth="1"
android:strokeColor="#cdcdcd"
android:strokeLineCap="round" />
<path
android:fillColor="#b2b2b7"
android:pathData="M39.8,35.98L43.06,35.98"
android:strokeWidth="1"
android:strokeColor="#cbcbcb"
android:strokeLineCap="round" />
<path
android:fillColor="#d0d0d4"
android:pathData="M32.77,29.99L34.4,32.81"
android:strokeWidth="1"
android:strokeColor="#ededed"
android:strokeLineCap="round" />
<path
android:fillColor="#949497"
android:pathData="M30.1,32.42L32.92,34.05"
android:strokeWidth="1"
android:strokeColor="#525252"
android:strokeLineCap="round" />
<path
android:fillColor="#97979b"
android:pathData="M32.42,35.98L29.16,35.98"
android:strokeWidth="1"
android:strokeColor="#6e6e6e"
android:strokeLineCap="round" />
<path
android:fillColor="#a8a8ac"
android:pathData="M36.06,43.08L36.06,39.82"
android:strokeWidth="1"
android:strokeColor="#a0a0a0"
android:strokeLineCap="round" />
<path
android:fillColor="#cacaca"
android:pathData="M39.7,41.99L38.07,39.16"
android:strokeWidth="1"
android:strokeColor="#cacaca"
android:strokeLineCap="round" />
<path
android:fillColor="#b6b6ba"
android:pathData="M42.19,39.4L39.37,37.77"
android:strokeWidth="1"
android:strokeColor="#ccc"
android:strokeLineCap="round" />
<path
android:fillColor="#a1a1a5"
android:pathData="M32.46,41.98L34.09,39.16"
android:strokeWidth="1"
android:strokeColor="#909090"
android:strokeLineCap="round" />
<path
android:fillColor="#9d9da0"
android:pathData="M29.85,39.4L32.67,37.77"
android:strokeWidth="1"
android:strokeColor="#7a7a7a"
android:strokeLineCap="round" />
</vector>

View File

@ -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
}