3 Lab
This commit is contained in:
parent
750e362438
commit
7f9450d02e
@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("com.google.devtools.ksp")
|
||||
}
|
||||
|
||||
android {
|
||||
@ -23,21 +24,24 @@ android {
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
jvmTarget = "17"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.4.3"
|
||||
kotlinCompilerExtensionVersion = "1.4.5"
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
@ -45,11 +49,16 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
//kotlin {
|
||||
//// jvmToolchain(11)
|
||||
//}
|
||||
|
||||
dependencies {
|
||||
|
||||
// Core
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
||||
|
||||
// UI
|
||||
implementation("androidx.activity:activity-compose:1.7.2")
|
||||
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||
implementation("androidx.navigation:navigation-compose:2.6.0")
|
||||
@ -57,9 +66,16 @@ dependencies {
|
||||
implementation("androidx.compose.ui:ui-graphics")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
implementation("io.coil-kt:coil-compose:2.2.2")
|
||||
implementation("io.coil-kt:coil-svg:2.2.2")
|
||||
|
||||
// Room
|
||||
val room_version = "2.5.2"
|
||||
implementation("androidx.room:room-runtime:$room_version")
|
||||
annotationProcessor("androidx.room:room-compiler:$room_version")
|
||||
ksp("androidx.room:room-compiler:$room_version")
|
||||
implementation("androidx.room:room-ktx:$room_version")
|
||||
implementation("androidx.room:room-paging:$room_version")
|
||||
|
||||
// Tests
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
@ -67,5 +83,4 @@ dependencies {
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.example.myapplication.Dishes.Model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
//enum class Category(
|
||||
// val value: String,
|
||||
//) {
|
||||
// CHICKEN("Chicken"),
|
||||
// BEEF("Beef"),
|
||||
// SOUP("Soup"),
|
||||
// DESSERT("Dessert"),
|
||||
// VEGETARIAN("Vegetarian"),
|
||||
// MILK("Milk"),
|
||||
// VEGAN("Vegan"),
|
||||
// PIZZA("Pizza"),
|
||||
// DONUT("Donut");
|
||||
//
|
||||
// companion object {
|
||||
// val allDishCategories = listOf(
|
||||
// CHICKEN, BEEF, SOUP, DESSERT, VEGETARIAN, MILK, VEGAN, PIZZA, DONUT
|
||||
// )
|
||||
//
|
||||
// fun getDishCategory(value: String): Category? {
|
||||
// val map = Category.values().associateBy(Category::value)
|
||||
// return map[value]
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@Entity(tableName="categories")
|
||||
data class Category(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name="category_id")
|
||||
val uid: Int?,
|
||||
@ColumnInfo(name = "category_name")
|
||||
val name: String
|
||||
) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Category
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
}
|
@ -1,45 +1,84 @@
|
||||
package com.example.myapplication.Dishes.Model
|
||||
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.User.Model.User
|
||||
import com.example.myapplication.User.Model.firstUser
|
||||
import com.example.myapplication.User.Model.secondUser
|
||||
import java.io.Serializable
|
||||
data class Dish (
|
||||
val name: String,
|
||||
val description: Int,
|
||||
val author: User,
|
||||
val category: DishCategory,
|
||||
val favorite: Boolean,
|
||||
val image: Int?
|
||||
) : Serializable
|
||||
|
||||
fun getAllDishes(): List<Dish> {
|
||||
return listOf(
|
||||
Dish("Pepperoni", R.string.lorem_ipsum,
|
||||
firstUser, DishCategory.PIZZA, false,
|
||||
R.drawable.pepperoni),
|
||||
Dish("Pepperoni", R.string.lorem_ipsum,
|
||||
secondUser, DishCategory.PIZZA, true,
|
||||
R.drawable.pepperoni),
|
||||
Dish("Sushi", R.string.lorem_ipsum, firstUser, DishCategory.CHICKEN, true, R.drawable.sushi),
|
||||
Dish("Pepperoni", R.string.lorem_ipsum,
|
||||
firstUser, DishCategory.PIZZA, false,
|
||||
R.drawable.pepperoni),
|
||||
Dish("Pepperoni", R.string.lorem_ipsum,
|
||||
secondUser, DishCategory.PIZZA, true,
|
||||
R.drawable.pepperoni),
|
||||
Dish("Sushi", R.string.lorem_ipsum, secondUser, DishCategory.CHICKEN, true, R.drawable.sushi),
|
||||
Dish("Pepperoni", R.string.lorem_ipsum,
|
||||
firstUser, DishCategory.PIZZA, false,
|
||||
R.drawable.pepperoni),
|
||||
Dish("Pepperoni", R.string.lorem_ipsum,
|
||||
secondUser, DishCategory.PIZZA, false,
|
||||
R.drawable.pepperoni),
|
||||
Dish("Sushi", R.string.lorem_ipsum, firstUser, DishCategory.CHICKEN, true, R.drawable.sushi)
|
||||
//data class Dish (
|
||||
// val name: String,
|
||||
// val description: Int,
|
||||
// val author: User,
|
||||
// val category: Category,
|
||||
// val favorite: Boolean,
|
||||
// val image: Int?
|
||||
//) : Serializable
|
||||
|
||||
//fun getAllDishes(): List<Dish> {
|
||||
// return listOf(
|
||||
//
|
||||
//}
|
||||
|
||||
@Entity(tableName = "dishes", foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = User::class,
|
||||
parentColumns = ["user_id"],
|
||||
childColumns = ["user_id"],
|
||||
onDelete = ForeignKey.NO_ACTION,
|
||||
onUpdate = ForeignKey.NO_ACTION
|
||||
),
|
||||
ForeignKey(
|
||||
entity = Category::class,
|
||||
parentColumns = ["category_id"],
|
||||
childColumns = ["category_id"],
|
||||
onDelete = ForeignKey.NO_ACTION,
|
||||
onUpdate = ForeignKey.NO_ACTION
|
||||
)
|
||||
}
|
||||
])
|
||||
data class Dish(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "dish_id")
|
||||
val uid: Int?,
|
||||
@ColumnInfo(name = "dish_name")
|
||||
val name: String,
|
||||
val description: String,
|
||||
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
|
||||
val image: ByteArray?,
|
||||
@ColumnInfo(name="user_id", index = true)
|
||||
val userId: Int?,
|
||||
@ColumnInfo(name="category_id", index = true)
|
||||
val categoryId: Int?
|
||||
) {
|
||||
@Ignore
|
||||
constructor(
|
||||
uid: Int?,
|
||||
name: String,
|
||||
description: String,
|
||||
image: ByteArray?,
|
||||
user: User,
|
||||
category: Category
|
||||
) : this (uid, name, description, image, user.uid, category.uid)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Dish
|
||||
if (uid != other.uid) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
|
||||
fun getBitmapFromByteArray(): Bitmap? {
|
||||
if (image == null) return null
|
||||
return BitmapFactory.decodeByteArray(image, 0, image.size)
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package com.example.myapplication.Dishes.Model
|
||||
|
||||
enum class DishCategory(
|
||||
val value: String,
|
||||
) {
|
||||
CHICKEN("Chicken"),
|
||||
BEEF("Beef"),
|
||||
SOUP("Soup"),
|
||||
DESSERT("Dessert"),
|
||||
VEGETARIAN("Vegetarian"),
|
||||
MILK("Milk"),
|
||||
VEGAN("Vegan"),
|
||||
PIZZA("Pizza"),
|
||||
DONUT("Donut");
|
||||
|
||||
companion object {
|
||||
val allDishCategories = listOf(
|
||||
CHICKEN, BEEF, SOUP, DESSERT, VEGETARIAN, MILK, VEGAN, PIZZA, DONUT
|
||||
)
|
||||
|
||||
fun getDishCategory(value: String): DishCategory? {
|
||||
val map = DishCategory.values().associateBy(DishCategory::value)
|
||||
return map[value]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.example.myapplication.Dishes.Model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Embedded
|
||||
|
||||
data class DishWithCategoryAndUser(
|
||||
@Embedded
|
||||
val dish: Dish?,
|
||||
@ColumnInfo(name="nickname")
|
||||
val nickname: String?,
|
||||
@ColumnInfo(name="category_name")
|
||||
val categoryName: String?,
|
||||
)
|
@ -0,0 +1,23 @@
|
||||
package com.example.myapplication.Dishes.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.Dishes.Model.Category
|
||||
|
||||
@Dao
|
||||
interface CategoryDao {
|
||||
@Query("select * from categories order by category_name collate nocase asc")
|
||||
fun getAll(): List<Category>
|
||||
|
||||
@Insert
|
||||
suspend fun insert(category: Category)
|
||||
|
||||
@Update
|
||||
suspend fun update(category: Category)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(category: Category)
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.example.myapplication.Dishes.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
import com.example.myapplication.Dishes.Model.DishWithCategoryAndUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface DishDao {
|
||||
@Query("select * from dishes order by dish_name collate nocase asc")
|
||||
fun getAll(): Flow<List<Dish>>
|
||||
|
||||
@Query("select * from dishes left join categories on dishes.category_id = categories.category_id " +
|
||||
"left join users on dishes.user_id = users.user_id where dishes.dish_id = :uid")
|
||||
suspend fun getByUid(uid: Int): DishWithCategoryAndUser
|
||||
|
||||
@Query("select * from dishes where dishes.user_id = :uid")
|
||||
fun getAllOFUser(uid: Int): Flow<List<Dish>>
|
||||
@Insert
|
||||
suspend fun insert(category: Dish)
|
||||
|
||||
@Update
|
||||
suspend fun update(category: Dish)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(category: Dish)
|
||||
}
|
@ -8,17 +8,28 @@ 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.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.FavoriteBorder
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@ -26,45 +37,98 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
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 androidx.navigation.NavController
|
||||
import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
//import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.User.Model.User
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
import com.example.myapplication.User.Model.UserFavorites
|
||||
import com.example.myapplication.database.AppDatabase
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import com.example.myapplication.ui.theme.textFont
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
fun DishList(navController: NavController?, onlyFavorites: Boolean = false, someUser: User? = null) {
|
||||
Column(Modifier.padding(horizontal = 10.dp, vertical = 5.dp).verticalScroll(ScrollState(0))) {
|
||||
fun DishList(navController: NavController?, onlyFavorites: Boolean = false, someUser: Int? = remember { null }, userPage: Boolean = false) {
|
||||
val context = LocalContext.current
|
||||
val dishes = remember { mutableStateListOf<Dish>() }
|
||||
val favoriteDishes = remember { mutableStateListOf<Dish>() }
|
||||
val scope = rememberCoroutineScope()
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
|
||||
if (someUser != null && onlyFavorites) {
|
||||
AppDatabase.getInstance(context).userFavoritesDao().getUserFavorites(someUser).collect() {data ->
|
||||
dishes.clear()
|
||||
favoriteDishes.clear()
|
||||
dishes.addAll(data)
|
||||
favoriteDishes.addAll(data)
|
||||
}
|
||||
}
|
||||
else if (someUser != null && userPage) {
|
||||
AppDatabase.getInstance(context).dishDao().getAllOFUser(someUser).collect() {data ->
|
||||
dishes.clear()
|
||||
favoriteDishes.clear()
|
||||
dishes.addAll(data)
|
||||
AppDatabase.getInstance(context).userFavoritesDao().getUserFavorites(someUser).collect() {data ->
|
||||
favoriteDishes.addAll(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
AppDatabase.getInstance(context).dishDao().getAll().collect() { data ->
|
||||
dishes.clear()
|
||||
favoriteDishes.clear()
|
||||
dishes.addAll(data)
|
||||
AppDatabase.getInstance(context).userFavoritesDao().getUserFavorites(someUser).collect() {data ->
|
||||
favoriteDishes.addAll(data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(ScrollState(0))) {
|
||||
|
||||
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
|
||||
Column {
|
||||
var text = stringResource(R.string.all_dishes)
|
||||
if (onlyFavorites) text = stringResource(id = R.string.favorite_dishes)
|
||||
if (someUser != null) text = stringResource(id = R.string.user_dishes)
|
||||
if (userPage) text = stringResource(id = R.string.user_dishes)
|
||||
Text(text, fontFamily= textFont,
|
||||
fontSize=26.sp, textAlign = TextAlign.Start)
|
||||
}
|
||||
}
|
||||
// TODO separate image with text
|
||||
getAllDishes().filter { it.author == someUser || someUser == null }.forEachIndexed() {index, dish ->
|
||||
if (onlyFavorites) {
|
||||
if (!dish.favorite) return@forEachIndexed;
|
||||
}
|
||||
val dishId = Screen.DishView.route.replace("{id}", index.toString())
|
||||
dishes.forEachIndexed() {index, dish ->
|
||||
Row(
|
||||
Modifier
|
||||
.padding(vertical = 5.dp)
|
||||
.fillMaxSize()
|
||||
.clickable {
|
||||
navController?.navigate(dishId)
|
||||
navController?.navigate("dish/" + dish.uid!!)
|
||||
}) {
|
||||
if (dish.image != null) {
|
||||
|
||||
Column() {
|
||||
if (dish.image != null) { // TODO Image input check
|
||||
Image(
|
||||
painter = painterResource(id = dish.image),
|
||||
bitmap = dish.getBitmapFromByteArray()!!.asImageBitmap(),
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.width(150.dp)
|
||||
)
|
||||
}
|
||||
else {
|
||||
Image(
|
||||
Icons.Filled.Warning,
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.width(150.dp)
|
||||
)
|
||||
@ -74,12 +138,44 @@ fun DishList(navController: NavController?, onlyFavorites: Boolean = false, some
|
||||
Text(dish.name, fontFamily=textFont,
|
||||
fontSize=15.sp, textAlign=TextAlign.Center )
|
||||
Text(
|
||||
stringResource(id = dish.description), fontFamily=textFont,
|
||||
dish.description, fontFamily=textFont,
|
||||
fontSize = 12.sp,
|
||||
softWrap = true,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 3)
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.clickable {
|
||||
scope.launch {
|
||||
if (favoriteDishes.contains(dish)) {
|
||||
AppDatabase
|
||||
.getInstance(context)
|
||||
.userFavoritesDao()
|
||||
.delete(
|
||||
UserFavorites(someUser!!, dish.uid!!)
|
||||
).run { favoriteDishes.clear() }
|
||||
|
||||
}
|
||||
else {
|
||||
AppDatabase
|
||||
.getInstance(context)
|
||||
.userFavoritesDao()
|
||||
.insert(
|
||||
UserFavorites(someUser!!, dish.uid!!)
|
||||
).run { favoriteDishes.clear() }
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(horizontal = 5.dp)
|
||||
) {
|
||||
if (favoriteDishes.contains(dish)) {
|
||||
Icon(Icons.Filled.Favorite, contentDescription = "")
|
||||
}
|
||||
else {
|
||||
Icon(Icons.Filled.FavoriteBorder, contentDescription = "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,12 +12,18 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@ -25,35 +31,57 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
import com.example.myapplication.Dishes.Model.DishWithCategoryAndUser
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.database.AppDatabase
|
||||
//import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import com.example.myapplication.ui.theme.textFont
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
fun DishView(id: Int) {
|
||||
val dish = getAllDishes()[id];
|
||||
var dish = remember { mutableStateOf(DishWithCategoryAndUser(
|
||||
Dish(0, "", "", null, null, null),
|
||||
null, null))
|
||||
}
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
dish.value = AppDatabase.getInstance(context).dishDao().getByUid(id)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp, horizontal = 10.dp)
|
||||
.verticalScroll(ScrollState(0))) {
|
||||
if (dish.image != null) {
|
||||
Row(Modifier.padding(vertical = 5.dp)) {
|
||||
if (dish.value.dish?.image != null) { // TODO Image input check
|
||||
Image(
|
||||
painter = painterResource(id = dish.image),
|
||||
bitmap = dish.value.dish!!.getBitmapFromByteArray()!!.asImageBitmap(),
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.fillMaxWidth(),
|
||||
Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
else {
|
||||
Image(
|
||||
painterResource(id = R.drawable.sushi),
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(horizontalArrangement = Arrangement.SpaceAround, modifier = Modifier.fillMaxWidth()) {
|
||||
Column {
|
||||
Text(dish.name, fontFamily=textFont,
|
||||
Text(dish.value.dish!!.name, fontFamily=textFont,
|
||||
fontSize=15.sp, textAlign = TextAlign.Start)
|
||||
}
|
||||
Column {
|
||||
Text("@" + dish.author.nickname, fontFamily=textFont,
|
||||
Text("@" + dish.value.nickname, fontFamily=textFont,
|
||||
fontSize=15.sp, textAlign = TextAlign.End)
|
||||
}
|
||||
}
|
||||
@ -63,7 +91,8 @@ fun DishView(id: Int) {
|
||||
horizontal = 30.dp, vertical = 10.dp
|
||||
)) {
|
||||
Text(
|
||||
stringResource(id = dish.description), fontFamily=textFont,
|
||||
dish.value.dish!!.description,
|
||||
fontFamily=textFont,
|
||||
fontSize = 13.sp,
|
||||
softWrap = true,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
|
@ -14,7 +14,9 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.example.myapplication.database.AppDatabase
|
||||
import com.example.myapplication.ui.navigation.MainNavbar
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
|
||||
@ -32,6 +34,7 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,42 @@
|
||||
package com.example.myapplication.User.Model
|
||||
|
||||
import android.provider.ContactsContract.CommonDataKinds.Nickname
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
import com.example.myapplication.Dishes.Model.DishCategory
|
||||
import com.example.myapplication.R
|
||||
import java.io.Serializable
|
||||
data class User (
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
//data class User (
|
||||
// val nickname: String,
|
||||
// val email: String,
|
||||
// val password: String
|
||||
//)
|
||||
//
|
||||
//val firstUser = User("UserNickname1", "UserEmail1", "UserPassword1")
|
||||
//val secondUser = User("UserNickname2", "UserEmail2", "UserPassword2")
|
||||
//fun getAllUsers(): List<User> {
|
||||
// return listOf(
|
||||
// firstUser, secondUser
|
||||
// )
|
||||
//}
|
||||
|
||||
@Entity(tableName = "users")
|
||||
data class User(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name="user_id")
|
||||
val uid: Int?,
|
||||
val nickname: String,
|
||||
val email: String,
|
||||
val password: String
|
||||
)
|
||||
val password: String,
|
||||
) {
|
||||
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
|
||||
}
|
||||
|
||||
val firstUser = User("UserNickname1", "UserEmail1", "UserPassword1")
|
||||
val secondUser = User("UserNickname2", "UserEmail2", "UserPassword2")
|
||||
fun getAllUsers(): List<User> {
|
||||
return listOf(
|
||||
firstUser, secondUser
|
||||
)
|
||||
override fun hashCode(): Int {
|
||||
return uid ?: -1
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.example.myapplication.User.Model;
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
|
||||
@Entity(tableName = "user_favorites", primaryKeys = ["user_id", "dish_id"])
|
||||
data class UserFavorites(
|
||||
@ColumnInfo(name = "user_id")
|
||||
val userId: Int,
|
||||
@ColumnInfo(name="dish_id")
|
||||
val dishId: Int
|
||||
) {
|
||||
@Ignore constructor(
|
||||
user: User,
|
||||
dish: Dish
|
||||
) : this (user.uid!!, dish.uid!!)
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.example.myapplication.User.Model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.Junction
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.Relation
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
|
||||
data class FavoriteWithUsers(
|
||||
@Embedded
|
||||
val dish: Dish,
|
||||
@Relation(
|
||||
parentColumn = "dish_id",
|
||||
entityColumn = "user_id",
|
||||
associateBy = Junction(UserFavorites::class)
|
||||
) val users: List<User>
|
||||
)
|
||||
|
||||
data class UserWithFavorites(
|
||||
@Embedded
|
||||
val user: User,
|
||||
@Relation(
|
||||
parentColumn = "user_id",
|
||||
entityColumn = "dish_id",
|
||||
associateBy = Junction(UserFavorites::class)
|
||||
) val favoriteDishes: List<Dish>
|
||||
)
|
@ -0,0 +1,33 @@
|
||||
package com.example.myapplication.User.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
import com.example.myapplication.User.Model.User
|
||||
import com.example.myapplication.User.Model.UserWithFavorites
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface UserDao {
|
||||
@Query("select * from users")
|
||||
fun getAll(): Flow<List<User>>
|
||||
|
||||
@Query("select * from users where users.user_id = :uid")
|
||||
suspend fun getByUid(uid: Int): User
|
||||
|
||||
|
||||
@Query("select * from user_favorites left join users on user_favorites.user_id = users.user_id " +
|
||||
"left join dishes on user_favorites.dish_id = dishes.dish_id WHERE user_favorites.user_id = :uid")
|
||||
suspend fun getFavorites(uid: Int): List<UserWithFavorites>
|
||||
@Insert
|
||||
suspend fun insert(user: User)
|
||||
|
||||
@Update
|
||||
suspend fun update(user: User)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(user: User)
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.example.myapplication.User.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
import com.example.myapplication.User.Model.User
|
||||
import com.example.myapplication.User.Model.UserFavorites
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface UserFavoritesDao {
|
||||
@Insert
|
||||
suspend fun insert(userFavorites: UserFavorites)
|
||||
|
||||
@Update
|
||||
suspend fun update(userFavorites: UserFavorites)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(userFavorites: UserFavorites)
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM dishes")
|
||||
fun getUserWithFavorites(): Flow<List<Dish>>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM user_favorites us JOIN dishes d ON d.dish_id = us.dish_id WHERE us.user_id = :uid")
|
||||
fun getUserFavorites(uid: Int?): Flow<List<Dish>>
|
||||
}
|
@ -9,11 +9,19 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.modifier.modifierLocalConsumer
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
@ -21,28 +29,43 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
//import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.Dishes.ui.DishList
|
||||
import com.example.myapplication.User.Model.getAllUsers
|
||||
import com.example.myapplication.User.Model.User
|
||||
import com.example.myapplication.database.AppDatabase
|
||||
//import com.example.myapplication.User.Model.getAllUsers
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import com.example.myapplication.ui.theme.textFont
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
fun UserView(id: Int, navController: NavController?) {
|
||||
val user = getAllUsers()[id];
|
||||
var user = remember { mutableStateOf(User(0, "", "", "")) }
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
user.value = AppDatabase.getInstance(context).userDao().getByUid(id)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp, horizontal = 10.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
|
||||
Column {
|
||||
Text(user.nickname, fontFamily= textFont,
|
||||
Text(user.value.nickname, fontFamily= textFont,
|
||||
fontSize=26.sp, textAlign = TextAlign.Start)
|
||||
}
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
// Button(onClick = { }, Modifier.fillMaxWidth()) {
|
||||
// Text("Create New Dish")
|
||||
// }
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
DishList(navController, someUser = user)
|
||||
DishList(navController, someUser = id, userPage = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,95 @@
|
||||
package com.example.myapplication.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.example.myapplication.Dishes.Model.Category
|
||||
import com.example.myapplication.Dishes.Model.Dish
|
||||
import com.example.myapplication.Dishes.dao.CategoryDao
|
||||
import com.example.myapplication.Dishes.dao.DishDao
|
||||
import com.example.myapplication.User.Model.User
|
||||
import com.example.myapplication.User.Model.UserFavorites
|
||||
import com.example.myapplication.User.Model.UserWithFavorites
|
||||
import com.example.myapplication.User.dao.UserDao
|
||||
import com.example.myapplication.User.dao.UserFavoritesDao
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Database(entities = [Dish::class, User::class, Category::class, UserFavorites::class],
|
||||
version = 1, exportSchema = false)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun dishDao() : DishDao
|
||||
abstract fun userDao() : UserDao
|
||||
abstract fun categoryDao() : CategoryDao
|
||||
abstract fun userFavoritesDao() : UserFavoritesDao
|
||||
|
||||
companion object {
|
||||
private const val DB_NAME: String = "food_warriors.db"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: AppDatabase? = null
|
||||
|
||||
private suspend fun populateDatabase() {
|
||||
INSTANCE?.let { database ->
|
||||
// Groups
|
||||
val categoryDao = database.categoryDao()
|
||||
val category = Category(1, "Pizza")
|
||||
val category1 = Category(2, "Sushi")
|
||||
categoryDao.insert(category)
|
||||
categoryDao.insert(category1)
|
||||
// Students
|
||||
val userDao = database.userDao()
|
||||
val user = User(1, "Nick1", "1@1.1", "123")
|
||||
val user1 = User(2, "Nick2", "1@1.1", "234")
|
||||
val user2 = User(3, "Nick3", "1@1.1", "345")
|
||||
val user3 = User(4, "Nick4", "1@1.1", "456")
|
||||
val user4 = User(5, "Nick5", "1@1.1", "567")
|
||||
userDao.insert(user)
|
||||
userDao.insert(user1)
|
||||
userDao.insert(user2)
|
||||
userDao.insert(user3)
|
||||
userDao.insert(user4)
|
||||
val dishDao = database.dishDao()
|
||||
val dish = Dish(1, "Peperoni", "Lorem ipsum", null, user, category)
|
||||
val dish1 = Dish(2, "Fish roll", "Lorem ipsum", null, user, category1)
|
||||
val dish2 = Dish(3, "Lazani", "Lorem ipsum", null, user1, category)
|
||||
dishDao.insert(dish)
|
||||
dishDao.insert(dish1)
|
||||
dishDao.insert(dish2)
|
||||
|
||||
val userFavoritesDao = database.userFavoritesDao()
|
||||
val userFavorites = UserFavorites(user, dish2)
|
||||
val userFavorites1 = UserFavorites(user3, dish1)
|
||||
val userFavorites2 = UserFavorites(user3, dish2)
|
||||
val userFavorites3 = UserFavorites(user1, dish)
|
||||
userFavoritesDao.insert(userFavorites)
|
||||
userFavoritesDao.insert(userFavorites1)
|
||||
userFavoritesDao.insert(userFavorites2)
|
||||
userFavoritesDao.insert(userFavorites3)
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,8 +12,11 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
@ -24,9 +27,14 @@ import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import com.example.myapplication.Dishes.ui.DishList
|
||||
import com.example.myapplication.Dishes.ui.DishView
|
||||
import com.example.myapplication.User.Model.User
|
||||
import com.example.myapplication.User.ui.UserView
|
||||
import com.example.myapplication.database.AppDatabase
|
||||
import com.example.myapplication.ui.components.Navbar
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
@ -35,14 +43,18 @@ fun Navhost(
|
||||
innerPadding: PaddingValues, modifier:
|
||||
Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var someUser: User? = null
|
||||
NavHost(
|
||||
navController,
|
||||
startDestination = Screen.AllDishes.route,
|
||||
modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(Screen.AllDishes.route) { DishList(navController) }
|
||||
composable(Screen.FavoriteDishes.route) { DishList(navController, true)}
|
||||
composable(Screen.UserPage.route) {UserView(id = 0, navController = navController)} // TODO Remove hardcode
|
||||
|
||||
|
||||
composable(Screen.AllDishes.route) { DishList(navController, someUser = 1) }
|
||||
composable(Screen.FavoriteDishes.route) { DishList(navController, true, 1)}
|
||||
composable(Screen.UserPage.route) {UserView(id = 1, navController = navController)} // TODO Remove hardcode
|
||||
|
||||
composable(Screen.DishView.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
|
@ -2,4 +2,5 @@
|
||||
plugins {
|
||||
id("com.android.application") version "8.1.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
|
||||
id("com.google.devtools.ksp") version "1.8.20-1.0.11" apply false
|
||||
}
|
Loading…
Reference in New Issue
Block a user