Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c81b83717 | |||
| 756cfa14c0 |
@@ -3,6 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:name=".FoodWarriorsApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.createSavedStateHandle
|
||||
import androidx.lifecycle.viewmodel.CreationExtras
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import com.example.myapplication.ui.dishes.list.DishListViewModel
|
||||
import com.example.myapplication.ui.dishes.view.CategoryDropDownViewModel
|
||||
import com.example.myapplication.ui.dishes.view.DishEditViewModel
|
||||
import com.example.myapplication.ui.dishes.view.DishViewModel
|
||||
import com.example.myapplication.ui.extra.ErrorsViewModel
|
||||
import com.example.myapplication.ui.user.UserViewModel
|
||||
|
||||
|
||||
object AppViewModelProvider {
|
||||
val Factory = viewModelFactory {
|
||||
initializer {
|
||||
DishListViewModel(foodWarriorsApplication().container.dishRepository,
|
||||
foodWarriorsApplication().container.userFavoritesRepository)
|
||||
}
|
||||
initializer {
|
||||
ErrorsViewModel()
|
||||
}
|
||||
initializer {
|
||||
UserViewModel(foodWarriorsApplication().container.userRepository)
|
||||
}
|
||||
initializer {
|
||||
DishViewModel(foodWarriorsApplication().container.dishRepository)
|
||||
}
|
||||
initializer {
|
||||
DishEditViewModel(
|
||||
this.createSavedStateHandle(),
|
||||
foodWarriorsApplication().container.dishRepository
|
||||
)
|
||||
}
|
||||
initializer {
|
||||
CategoryDropDownViewModel(foodWarriorsApplication().container.categoryRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun CreationExtras.foodWarriorsApplication(): FoodWarriorsApplication =
|
||||
(this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as FoodWarriorsApplication)
|
||||
@@ -1,195 +0,0 @@
|
||||
package com.example.myapplication.Dishes.ui
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.ScrollState
|
||||
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.fillMaxSize
|
||||
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.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
|
||||
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.Dish
|
||||
//import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.User.Model.User
|
||||
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: 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 (userPage) text = stringResource(id = R.string.user_dishes)
|
||||
Text(text, fontFamily= textFont,
|
||||
fontSize=26.sp, textAlign = TextAlign.Start)
|
||||
}
|
||||
}
|
||||
dishes.forEachIndexed() {index, dish ->
|
||||
Row(
|
||||
Modifier
|
||||
.padding(vertical = 5.dp)
|
||||
.fillMaxSize()
|
||||
.clickable {
|
||||
navController?.navigate("dish/" + dish.uid!!)
|
||||
}) {
|
||||
|
||||
Column() {
|
||||
if (dish.image != null) { // TODO Image input check
|
||||
Image(
|
||||
bitmap = dish.getBitmapFromByteArray()!!.asImageBitmap(),
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.width(150.dp)
|
||||
)
|
||||
}
|
||||
else {
|
||||
Image(
|
||||
Icons.Filled.Warning,
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.width(150.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Column {
|
||||
Text(dish.name, fontFamily=textFont,
|
||||
fontSize=15.sp, textAlign=TextAlign.Center )
|
||||
Text(
|
||||
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 = "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Preview
|
||||
@Composable
|
||||
fun ListDishes() {
|
||||
MyApplicationTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
DishList(navController = null, onlyFavorites = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.example.myapplication
|
||||
|
||||
import android.app.Application
|
||||
import com.example.myapplication.database.AppContainer
|
||||
import com.example.myapplication.database.AppDataContainer
|
||||
|
||||
class FoodWarriorsApplication : Application() {
|
||||
lateinit var container: AppContainer
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
container = AppDataContainer(this)
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package com.example.myapplication.User.ui
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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
|
||||
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.ui.DishList
|
||||
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?) {
|
||||
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.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 = id, userPage = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Preview
|
||||
@Composable
|
||||
fun UserPreview() {
|
||||
MyApplicationTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
UserView(id = 0, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.example.myapplication.database
|
||||
|
||||
import android.content.Context
|
||||
import com.example.myapplication.database.repository.CategoryRepository
|
||||
import com.example.myapplication.database.repository.DishRepository
|
||||
import com.example.myapplication.database.repository.OfflineCategoryRepository
|
||||
import com.example.myapplication.database.repository.OfflineDishRepository
|
||||
import com.example.myapplication.database.repository.OfflineUserFavoritesRepository
|
||||
import com.example.myapplication.database.repository.OfflineUserRepository
|
||||
import com.example.myapplication.database.repository.UserRepository
|
||||
import com.example.myapplication.database.repository.UserWithFavoritesRepository
|
||||
|
||||
|
||||
interface AppContainer {
|
||||
val userRepository : UserRepository
|
||||
val dishRepository : DishRepository
|
||||
val categoryRepository : CategoryRepository
|
||||
val userFavoritesRepository: UserWithFavoritesRepository
|
||||
}
|
||||
|
||||
class AppDataContainer(private val context: Context) : AppContainer {
|
||||
|
||||
override val userRepository: UserRepository by lazy {
|
||||
OfflineUserRepository(AppDatabase.getInstance(context).userDao())
|
||||
}
|
||||
|
||||
override val dishRepository: DishRepository by lazy {
|
||||
OfflineDishRepository(AppDatabase.getInstance(context).dishDao())
|
||||
}
|
||||
|
||||
override val categoryRepository: CategoryRepository by lazy {
|
||||
OfflineCategoryRepository(AppDatabase.getInstance(context).categoryDao())
|
||||
}
|
||||
|
||||
override val userFavoritesRepository: UserWithFavoritesRepository by lazy {
|
||||
OfflineUserFavoritesRepository(AppDatabase.getInstance(context).userFavoritesDao())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TIMEOUT = 5000L
|
||||
}
|
||||
}
|
||||
@@ -5,15 +5,14 @@ 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 com.example.myapplication.database.model.Category
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.dao.CategoryDao
|
||||
import com.example.myapplication.database.dao.DishDao
|
||||
import com.example.myapplication.database.model.User
|
||||
import com.example.myapplication.database.model.UserFavorites
|
||||
import com.example.myapplication.database.dao.UserDao
|
||||
import com.example.myapplication.database.dao.UserFavoritesDao
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package com.example.myapplication.Dishes.dao
|
||||
package com.example.myapplication.database.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
|
||||
import com.example.myapplication.database.model.Category
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface CategoryDao {
|
||||
@Query("select * from categories order by category_name collate nocase asc")
|
||||
fun getAll(): List<Category>
|
||||
suspend fun getAll(): List<Category>
|
||||
|
||||
@Insert
|
||||
suspend fun insert(category: Category)
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.example.myapplication.Dishes.dao
|
||||
package com.example.myapplication.database.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 com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.DishWithCategoryAndUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
@@ -16,7 +16,7 @@ interface DishDao {
|
||||
|
||||
@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
|
||||
fun getByUid(uid: Int): Flow<DishWithCategoryAndUser?>
|
||||
|
||||
@Query("select * from dishes where dishes.user_id = :uid")
|
||||
fun getAllOFUser(uid: Int): Flow<List<Dish>>
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.example.myapplication.User.dao
|
||||
package com.example.myapplication.database.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 com.example.myapplication.database.model.User
|
||||
import com.example.myapplication.database.model.UserWithFavorites
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
@@ -16,7 +15,7 @@ interface UserDao {
|
||||
fun getAll(): Flow<List<User>>
|
||||
|
||||
@Query("select * from users where users.user_id = :uid")
|
||||
suspend fun getByUid(uid: Int): User
|
||||
fun getByUid(uid: Int): Flow<User?>
|
||||
|
||||
|
||||
@Query("select * from user_favorites left join users on user_favorites.user_id = users.user_id " +
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.myapplication.User.dao
|
||||
package com.example.myapplication.database.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
@@ -6,9 +6,9 @@ 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 com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.User
|
||||
import com.example.myapplication.database.model.UserFavorites
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
@@ -29,4 +29,8 @@ interface UserFavoritesDao {
|
||||
@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>>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM user_favorites us WHERE us.user_id = :userUid AND us.dish_id = :dishUid")
|
||||
fun getUserFavorite(userUid: Int?, dishUid: Int?): Flow<UserFavorites?>
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.myapplication.Dishes.Model
|
||||
package com.example.myapplication.database.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.myapplication.Dishes.Model
|
||||
package com.example.myapplication.database.model
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
@@ -7,9 +7,6 @@ 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 java.io.Serializable
|
||||
|
||||
//data class Dish (
|
||||
// val name: String,
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.myapplication.Dishes.Model
|
||||
package com.example.myapplication.database.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Embedded
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.example.myapplication.User.Model
|
||||
package com.example.myapplication.database.model
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
//data class User (
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.example.myapplication.User.Model;
|
||||
package com.example.myapplication.database.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(
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.example.myapplication.User.Model
|
||||
package com.example.myapplication.database.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
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.model.Category
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface CategoryRepository {
|
||||
suspend fun getAllCategories(): List<Category>
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.DishWithCategoryAndUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface DishRepository {
|
||||
fun getAllDishes(): Flow<List<Dish>>
|
||||
fun getDish(uid: Int): Flow<DishWithCategoryAndUser?>
|
||||
|
||||
fun getUserDishes(userUid: Int) : Flow<List<Dish>>
|
||||
suspend fun insertDish(dish: Dish)
|
||||
suspend fun updateDish(dish: Dish)
|
||||
suspend fun deleteDish(dish: Dish)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.dao.CategoryDao
|
||||
import com.example.myapplication.database.model.Category
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineCategoryRepository(private val categoryDao: CategoryDao) : CategoryRepository {
|
||||
override suspend fun getAllCategories(): List<Category> {
|
||||
return categoryDao.getAll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.dao.DishDao
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.DishWithCategoryAndUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineDishRepository(private val dishDao: DishDao) : DishRepository {
|
||||
override fun getAllDishes(): Flow<List<Dish>> {
|
||||
return dishDao.getAll()
|
||||
}
|
||||
|
||||
override fun getDish(uid: Int): Flow<DishWithCategoryAndUser?> {
|
||||
return dishDao.getByUid(uid)
|
||||
}
|
||||
|
||||
override fun getUserDishes(userUid: Int): Flow<List<Dish>> {
|
||||
return dishDao.getAllOFUser(userUid);
|
||||
}
|
||||
|
||||
override suspend fun insertDish(dish: Dish) {
|
||||
dishDao.insert(dish)
|
||||
}
|
||||
|
||||
override suspend fun updateDish(dish: Dish) {
|
||||
dishDao.update(dish)
|
||||
}
|
||||
|
||||
override suspend fun deleteDish(dish: Dish) {
|
||||
dishDao.delete(dish)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.dao.UserFavoritesDao
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.UserFavorites
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineUserFavoritesRepository(private val userFavoritesDao: UserFavoritesDao) : UserWithFavoritesRepository {
|
||||
override fun getUserFavorites(userUid: Int): Flow<List<Dish>> {
|
||||
return userFavoritesDao.getUserFavorites(userUid)
|
||||
}
|
||||
|
||||
override fun getUserFavorite(userUid: Int, dishUid: Int): Flow<UserFavorites?> {
|
||||
return userFavoritesDao.getUserFavorite(userUid, dishUid)
|
||||
}
|
||||
|
||||
override suspend fun deleteUserFavorites(userUid: Int, dishUid: Int) {
|
||||
userFavoritesDao.delete(UserFavorites(userUid, dishUid))
|
||||
}
|
||||
|
||||
override suspend fun insertUserFavorites(userUid: Int, dishUid: Int) {
|
||||
userFavoritesDao.insert(UserFavorites(userUid, dishUid))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.dao.UserDao
|
||||
import com.example.myapplication.database.model.User
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
|
||||
override fun getAllUsers(): Flow<List<User>> {
|
||||
return userDao.getAll()
|
||||
}
|
||||
|
||||
override fun getUser(uid: Int): Flow<User?> {
|
||||
return userDao.getByUid(uid)
|
||||
}
|
||||
|
||||
override suspend fun insertUser(user: User) {
|
||||
userDao.insert(user)
|
||||
}
|
||||
|
||||
override suspend fun updateUser(user: User) {
|
||||
userDao.update(user)
|
||||
}
|
||||
|
||||
override suspend fun deleteUser(user: User) {
|
||||
userDao.delete(user)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.model.User
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface UserRepository {
|
||||
fun getAllUsers(): Flow<List<User>>
|
||||
fun getUser(uid: Int): Flow<User?>
|
||||
suspend fun insertUser(user: User)
|
||||
suspend fun updateUser(user: User)
|
||||
suspend fun deleteUser(user: User)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.myapplication.database.repository
|
||||
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.UserFavorites
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface UserWithFavoritesRepository {
|
||||
fun getUserFavorites(userUid: Int): Flow<List<Dish>>
|
||||
|
||||
fun getUserFavorite(userUid: Int, dishUid: Int): Flow<UserFavorites?>
|
||||
|
||||
suspend fun deleteUserFavorites(userUid: Int, dishUid: Int)
|
||||
|
||||
suspend fun insertUserFavorites(userUid: Int, dishUid: Int)
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package com.example.myapplication.ui.dishes.list
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.ScrollState
|
||||
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.fillMaxSize
|
||||
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.Favorite
|
||||
import androidx.compose.material.icons.filled.FavoriteBorder
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.AppViewModelProvider
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.database.model.UserFavorites
|
||||
import com.example.myapplication.database.AppDatabase
|
||||
import com.example.myapplication.database.model.User
|
||||
import com.example.myapplication.ui.extra.ErrorElement
|
||||
import com.example.myapplication.ui.extra.ErrorsType
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
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
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
fun DishList(
|
||||
navController: NavController,
|
||||
viewModel: DishListViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
typeDishList: TypeDishList = TypeDishList.AllDishes,
|
||||
userUid: Int?
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val dishListUiState by viewModel.dishListUiState.collectAsState()
|
||||
val userDishes by viewModel.userDishes(userUid ?: 0).collectAsState()
|
||||
val favorites by viewModel.dishFavorites(userUid ?: 0).collectAsState()
|
||||
Scaffold(
|
||||
) { innerPadding ->
|
||||
if (typeDishList != TypeDishList.AllDishes && userUid == null) {
|
||||
ErrorElement(navController = navController, typeErrorsType = ErrorsType.NOT_AUTH)
|
||||
}
|
||||
else {
|
||||
DishList(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(ScrollState(0)),
|
||||
typeDishList = typeDishList,
|
||||
dishList = when (typeDishList) {
|
||||
TypeDishList.AllDishes -> dishListUiState.dishList
|
||||
TypeDishList.FavoritesDishes -> favorites.dishList
|
||||
TypeDishList.UserDishes -> userDishes.dishList
|
||||
else -> dishListUiState.dishList
|
||||
},
|
||||
favorites = favorites.dishList,
|
||||
addToFavorites = {uid: Int ->
|
||||
if (userUid != null) {
|
||||
coroutineScope.launch {
|
||||
viewModel.addFavoritesToUser(userUid, uid)
|
||||
}
|
||||
}
|
||||
},
|
||||
onClick = {uid: Int ->
|
||||
val route = Screen.DishView.route.replace("{id}", uid.toString())
|
||||
navController.navigate(route)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
private fun DishList(
|
||||
modifier: Modifier = Modifier,
|
||||
typeDishList: TypeDishList,
|
||||
dishList: List<Dish>,
|
||||
favorites: List<Dish>,
|
||||
addToFavorites: (uid : Int) -> Unit,
|
||||
onClick: (uid : Int) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
|
||||
Column {
|
||||
val text: String = when (typeDishList) {
|
||||
TypeDishList.AllDishes -> stringResource(R.string.all_dishes)
|
||||
TypeDishList.FavoritesDishes -> stringResource(id = R.string.favorite_dishes)
|
||||
TypeDishList.UserDishes -> stringResource(id = R.string.user_dishes)
|
||||
else -> ""
|
||||
}
|
||||
|
||||
Text(text, fontFamily= textFont,
|
||||
fontSize=26.sp, textAlign = TextAlign.Start)
|
||||
}
|
||||
}
|
||||
dishList.forEachIndexed() {index, dish ->
|
||||
DishListItem(index=index, dish = dish, favorites = favorites, addToFavorites, onClick = onClick)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
private fun DishListItem(
|
||||
index: Int,
|
||||
dish: Dish,
|
||||
favorites: List<Dish>,
|
||||
addToFavorites: (uid : Int) -> Unit,
|
||||
onClick: (uid: Int) -> Unit
|
||||
) {
|
||||
Row(
|
||||
Modifier
|
||||
.padding(vertical = 5.dp)
|
||||
.fillMaxSize()
|
||||
.clickable {
|
||||
onClick(dish.uid!!)
|
||||
}) {
|
||||
|
||||
Column() {
|
||||
if (dish.image != null) { // TODO Image input check
|
||||
Image(
|
||||
bitmap = dish.getBitmapFromByteArray()!!.asImageBitmap(),
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.width(150.dp)
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
Icons.Filled.Warning,
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.width(150.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Column {
|
||||
Text(
|
||||
dish.name, fontFamily = textFont,
|
||||
fontSize = 15.sp, textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
dish.description, fontFamily = textFont,
|
||||
fontSize = 12.sp,
|
||||
softWrap = true,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 3
|
||||
)
|
||||
}
|
||||
Column(
|
||||
Modifier.clickable { addToFavorites(dish.uid!!) }
|
||||
) {
|
||||
if (favorites.contains(dish)) {
|
||||
Icon(Icons.Filled.Favorite, contentDescription = "")
|
||||
}
|
||||
else {
|
||||
Icon(Icons.Filled.FavoriteBorder, contentDescription = "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Preview
|
||||
@Composable
|
||||
fun ListDishes() {
|
||||
// MyApplicationTheme {
|
||||
// Surface(
|
||||
// color = MaterialTheme.colorScheme.background
|
||||
// ) {
|
||||
// DishList(navController = null, onlyFavorites = false)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.example.myapplication.ui.dishes.list
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.database.AppDataContainer
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.repository.DishRepository
|
||||
import com.example.myapplication.database.repository.UserWithFavoritesRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
enum class TypeDishList {
|
||||
AllDishes,
|
||||
FavoritesDishes,
|
||||
UserDishes
|
||||
}
|
||||
class DishListViewModel(
|
||||
private val dishRepository: DishRepository,
|
||||
private val userWithFavoritesRepository: UserWithFavoritesRepository
|
||||
) : ViewModel() {
|
||||
val dishListUiState: StateFlow<DishListUiState> = dishRepository.getAllDishes().map {
|
||||
DishListUiState(it)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
|
||||
initialValue = DishListUiState()
|
||||
)
|
||||
|
||||
fun dishFavorites(userUid: Int) : StateFlow<DishListUiState> {
|
||||
return userWithFavoritesRepository.getUserFavorites(userUid).map {
|
||||
DishListUiState(it)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
|
||||
initialValue = DishListUiState()
|
||||
)
|
||||
}
|
||||
|
||||
fun userDishes(userUid: Int) : StateFlow<DishListUiState> {
|
||||
return dishRepository.getUserDishes(userUid).map {
|
||||
DishListUiState(it)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
|
||||
initialValue = DishListUiState()
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun addFavoritesToUser(userUid: Int, dishUid: Int) {
|
||||
var flag = true;
|
||||
userWithFavoritesRepository.getUserFavorite(userUid, dishUid).collect {
|
||||
if (flag) {
|
||||
if (it == null) {
|
||||
flag = false
|
||||
userWithFavoritesRepository.insertUserFavorites(userUid, dishUid)
|
||||
} else {
|
||||
flag = false
|
||||
userWithFavoritesRepository.deleteUserFavorites(userUid, dishUid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class DishListUiState(val dishList: List<Dish> = listOf())
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.example.myapplication.ui.dishes.view
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.database.model.Category
|
||||
import com.example.myapplication.database.repository.CategoryRepository
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CategoryDropDownViewModel(
|
||||
private val categoryRepository: CategoryRepository
|
||||
) : ViewModel() {
|
||||
var categoryListUiState by mutableStateOf(CategoryListUiState())
|
||||
private set
|
||||
|
||||
var categoryUiState by mutableStateOf(CategoryUiState())
|
||||
private set
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
categoryListUiState = CategoryListUiState(categoryRepository.getAllCategories())
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentCategory(categoryId: Int) {
|
||||
val category: Category? =
|
||||
categoryListUiState.categoryList.firstOrNull { category -> category.uid == categoryId }
|
||||
category?.let { updateUiState(it) }
|
||||
}
|
||||
|
||||
fun updateUiState(category: Category) {
|
||||
categoryUiState = CategoryUiState(
|
||||
category = category
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class CategoryListUiState(val categoryList: List<Category> = listOf())
|
||||
|
||||
data class CategoryUiState(
|
||||
val category: Category? = null
|
||||
)
|
||||
|
||||
fun Category.toUiState() = CategoryUiState(category = Category(uid = uid, name = name))
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.example.myapplication.ui.dishes.view
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.AppViewModelProvider
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.database.model.Category
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DishEditView (
|
||||
navController: NavController,
|
||||
viewModel: DishEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
categoryViewModel: CategoryDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
userUid: Int
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
categoryViewModel.setCurrentCategory(viewModel.dishEditUiState.dishDetails.categoryUid!!)
|
||||
viewModel.setCurrentUser(userUid)
|
||||
DishEditView(
|
||||
dishUiState = viewModel.dishEditUiState,
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveDish()
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
onUpdate = viewModel::updateUiState,
|
||||
categoryUiState = categoryViewModel.categoryUiState,
|
||||
categoryListUiState = categoryViewModel.categoryListUiState,
|
||||
onCategoryUpdate = categoryViewModel::updateUiState
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun CategoryDropDown(
|
||||
categoryUiState: CategoryUiState,
|
||||
categoryListUiState: CategoryListUiState,
|
||||
onCategoryUpdate: (Category) -> Unit
|
||||
) {
|
||||
var expanded: Boolean by remember { mutableStateOf(false) }
|
||||
ExposedDropdownMenuBox(
|
||||
modifier = Modifier
|
||||
.padding(top = 7.dp),
|
||||
expanded = expanded,
|
||||
onExpandedChange = {
|
||||
expanded = !expanded
|
||||
}
|
||||
) {
|
||||
TextField(
|
||||
value = categoryUiState.category?.name
|
||||
?: stringResource(id = R.string.category_not_found),
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
trailingIcon = {
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.menuAnchor()
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false },
|
||||
modifier = Modifier
|
||||
.background(Color.White)
|
||||
.exposedDropdownSize()
|
||||
) {
|
||||
categoryListUiState.categoryList.forEach { category ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = category.name)
|
||||
},
|
||||
onClick = {
|
||||
onCategoryUpdate(category)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun DishEditView(
|
||||
dishUiState: DishEditUiState,
|
||||
categoryUiState: CategoryUiState,
|
||||
categoryListUiState: CategoryListUiState,
|
||||
onClick: () -> Unit,
|
||||
onUpdate: (DishDetails) -> Unit,
|
||||
onCategoryUpdate: (Category) -> Unit
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 10.dp)
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = dishUiState.dishDetails.name,
|
||||
onValueChange = { onUpdate(dishUiState.dishDetails.copy(name = it)) },
|
||||
label = { Text(stringResource(id = R.string.dish_label)) },
|
||||
singleLine = true
|
||||
)
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = dishUiState.dishDetails.description,
|
||||
onValueChange = { onUpdate(dishUiState.dishDetails.copy(description = it)) },
|
||||
label = { Text(stringResource(id = R.string.dish_description)) },
|
||||
singleLine = true
|
||||
)
|
||||
CategoryDropDown(
|
||||
categoryUiState = categoryUiState,
|
||||
categoryListUiState = categoryListUiState,
|
||||
onCategoryUpdate = {
|
||||
onUpdate(dishUiState.dishDetails.copy(categoryUid = it.uid))
|
||||
onCategoryUpdate(it)
|
||||
}
|
||||
)
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = dishUiState.isEntryValid,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(R.string.dish_save))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.example.myapplication.ui.dishes.view
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.database.model.Category
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.User
|
||||
import com.example.myapplication.database.repository.DishRepository
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class DishEditViewModel (
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val dishRepository: DishRepository
|
||||
) : ViewModel() {
|
||||
var dishEditUiState by mutableStateOf(DishEditUiState())
|
||||
private set
|
||||
|
||||
private val dishUid: Int = checkNotNull(savedStateHandle["id"])
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
if (dishUid > 0) {
|
||||
dishEditUiState = dishRepository.getDish(dishUid)
|
||||
.filterNotNull()
|
||||
.first().dish!!
|
||||
.toUiState(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun updateUiState(dishDetails: DishDetails) {
|
||||
dishEditUiState = DishEditUiState(
|
||||
dishDetails = dishDetails,
|
||||
isEntryValid = validateInput(dishDetails)
|
||||
)
|
||||
}
|
||||
|
||||
fun setCurrentUser(userId: Int) {
|
||||
val dish: DishDetails? =
|
||||
dishEditUiState.dishDetails.copy(userUid = userId)
|
||||
dish?.let { updateUiState(it) }
|
||||
}
|
||||
suspend fun saveDish() {
|
||||
if (validateInput()) {
|
||||
if (dishUid > 0) {
|
||||
dishRepository.updateDish(dishEditUiState.dishDetails.toDish(dishUid))
|
||||
} else {
|
||||
// dishEditUiState.dishDetails.copy(uid)
|
||||
dishRepository.insertDish(dishEditUiState.dishDetails.toDish())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateInput(uiState: DishDetails = dishEditUiState.dishDetails): Boolean {
|
||||
return with(uiState) {
|
||||
name.isNotBlank()
|
||||
&& description.isNotBlank()
|
||||
&& userUid!! > 0
|
||||
&& categoryUid!! > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class DishEditUiState(
|
||||
val dishDetails: DishDetails = DishDetails(),
|
||||
val isEntryValid: Boolean = false
|
||||
)
|
||||
data class DishDetails(
|
||||
val name: String = "",
|
||||
val description: String = "",
|
||||
val image: ByteArray? = null,
|
||||
val userUid: Int? = 0,
|
||||
val categoryUid: Int? = 0
|
||||
)
|
||||
|
||||
fun DishDetails.toDish(uid: Int? = null): Dish = Dish(
|
||||
uid = uid,
|
||||
name = name,
|
||||
description = description,
|
||||
image = image,
|
||||
userId = userUid,
|
||||
categoryId = categoryUid
|
||||
)
|
||||
|
||||
fun Dish.toDetails(): DishDetails = DishDetails(
|
||||
name = name,
|
||||
description = description,
|
||||
image = image,
|
||||
userUid = userId,
|
||||
categoryUid = categoryId
|
||||
)
|
||||
|
||||
fun Dish.toUiState(isEntryValid: Boolean = false): DishEditUiState = DishEditUiState(
|
||||
dishDetails = this.toDetails(),
|
||||
isEntryValid = isEntryValid
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.myapplication.Dishes.ui
|
||||
package com.example.myapplication.ui.dishes
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
@@ -10,59 +10,102 @@ 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.foundation.layout.width
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.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
|
||||
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.Dish
|
||||
import com.example.myapplication.Dishes.Model.DishWithCategoryAndUser
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.AppViewModelProvider
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.DishWithCategoryAndUser
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.database.AppDatabase
|
||||
import com.example.myapplication.ui.dishes.view.DishViewModel
|
||||
import com.example.myapplication.ui.extra.ErrorElement
|
||||
import com.example.myapplication.ui.extra.ErrorsType
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
//import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import com.example.myapplication.ui.theme.textFont
|
||||
import com.example.myapplication.ui.user.UserViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DishView(id: Int) {
|
||||
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)
|
||||
fun DishView(navController: NavController,
|
||||
viewModel: DishViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
userUid: Int?,
|
||||
dishUid: Int?) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val dishUiState by viewModel.getDish(dishUid ?: 0).collectAsState()
|
||||
Scaffold(
|
||||
floatingActionButton = {
|
||||
if (dishUiState.dish?.dish?.userId == userUid) {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
val route = Screen.DishEdit.route.replace("{id}", dishUid.toString())
|
||||
navController.navigate(route)
|
||||
},
|
||||
) {
|
||||
Icon(Icons.Filled.Add, "Добавить")
|
||||
}
|
||||
}
|
||||
}
|
||||
){ innerPadding ->
|
||||
if (dishUiState.dish == null) {
|
||||
ErrorElement(navController = navController, typeErrorsType = ErrorsType.NOT_FOUND)
|
||||
}
|
||||
else {
|
||||
DishView(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
dish = dishUiState.dish!!
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
private fun DishView(
|
||||
modifier: Modifier,
|
||||
dish : DishWithCategoryAndUser
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp, horizontal = 10.dp)
|
||||
.verticalScroll(ScrollState(0))) {
|
||||
Row(Modifier.padding(vertical = 5.dp)) {
|
||||
if (dish.value.dish?.image != null) { // TODO Image input check
|
||||
if (dish.dish?.image != null) {
|
||||
Image(
|
||||
bitmap = dish.value.dish!!.getBitmapFromByteArray()!!.asImageBitmap(),
|
||||
bitmap = dish.dish.getBitmapFromByteArray()!!.asImageBitmap(),
|
||||
contentDescription = "Dish Image",
|
||||
Modifier.fillMaxSize()
|
||||
)
|
||||
@@ -77,11 +120,11 @@ fun DishView(id: Int) {
|
||||
}
|
||||
Row(horizontalArrangement = Arrangement.SpaceAround, modifier = Modifier.fillMaxWidth()) {
|
||||
Column {
|
||||
Text(dish.value.dish!!.name, fontFamily=textFont,
|
||||
Text(dish.dish!!.name, fontFamily=textFont,
|
||||
fontSize=15.sp, textAlign = TextAlign.Start)
|
||||
}
|
||||
Column {
|
||||
Text("@" + dish.value.nickname, fontFamily=textFont,
|
||||
Text("@" + dish.nickname, fontFamily=textFont,
|
||||
fontSize=15.sp, textAlign = TextAlign.End)
|
||||
}
|
||||
}
|
||||
@@ -89,9 +132,10 @@ fun DishView(id: Int) {
|
||||
.fillMaxSize()
|
||||
.padding(
|
||||
horizontal = 30.dp, vertical = 10.dp
|
||||
)) {
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
dish.value.dish!!.description,
|
||||
dish.dish!!.description,
|
||||
fontFamily=textFont,
|
||||
fontSize = 13.sp,
|
||||
softWrap = true,
|
||||
@@ -100,16 +144,3 @@ fun DishView(id: Int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Preview
|
||||
@Composable
|
||||
fun DishPreview() {
|
||||
MyApplicationTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
DishView(id = 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.example.myapplication.ui.dishes.view
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.database.AppDataContainer
|
||||
import com.example.myapplication.database.model.DishWithCategoryAndUser
|
||||
import com.example.myapplication.database.repository.DishRepository
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
class DishViewModel(
|
||||
private val dishRepository: DishRepository
|
||||
) : ViewModel() {
|
||||
fun getDish(uid: Int) : StateFlow<DishViewUiState> {
|
||||
return dishRepository.getDish(uid).map {
|
||||
DishViewUiState(it!!)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
|
||||
initialValue = DishViewUiState()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class DishViewUiState(val dish: DishWithCategoryAndUser? = null)
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.example.myapplication.ui.extra
|
||||
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import com.example.myapplication.AppViewModelProvider
|
||||
import com.example.myapplication.ui.dishes.list.DishList
|
||||
import com.example.myapplication.ui.dishes.list.DishListViewModel
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ErrorElement(
|
||||
navController: NavController,
|
||||
viewModel: ErrorsViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
typeErrorsType: ErrorsType
|
||||
) {
|
||||
Scaffold(
|
||||
) { innerPadding ->
|
||||
ErrorElement(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
text = viewModel.getError(typeErrorsType).errorText
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ErrorElement(
|
||||
modifier: Modifier,
|
||||
text: String
|
||||
) {
|
||||
Text(text = text)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.example.myapplication.ui.extra
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.database.AppDataContainer
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.ui.dishes.list.DishListUiState
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
enum class ErrorsType {
|
||||
NOT_AUTH,
|
||||
NOT_FOUND
|
||||
}
|
||||
class ErrorsViewModel : ViewModel() {
|
||||
fun getError(type: ErrorsType) : ErrorUiState {
|
||||
return when (type) {
|
||||
ErrorsType.NOT_AUTH -> ErrorUiState("Auth first")
|
||||
ErrorsType.NOT_FOUND -> ErrorUiState("Not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class ErrorUiState(val errorText: String = "")
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.example.myapplication.ui.navigation
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.background
|
||||
@@ -12,9 +11,7 @@ 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
|
||||
@@ -25,16 +22,16 @@ import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
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.dishes.list.DishList
|
||||
//import com.example.myapplication.ui.dishes.DishView
|
||||
import com.example.myapplication.database.model.User
|
||||
//import com.example.myapplication.ui.user.UserView
|
||||
import com.example.myapplication.ui.components.Navbar
|
||||
import com.example.myapplication.ui.dishes.DishView
|
||||
import com.example.myapplication.ui.dishes.list.TypeDishList
|
||||
import com.example.myapplication.ui.dishes.view.DishEditView
|
||||
import com.example.myapplication.ui.theme.MyApplicationTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.example.myapplication.ui.user.UserView
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
@@ -43,8 +40,7 @@ fun Navhost(
|
||||
innerPadding: PaddingValues, modifier:
|
||||
Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var someUser: User? = null
|
||||
val userUid = 1;
|
||||
NavHost(
|
||||
navController,
|
||||
startDestination = Screen.AllDishes.route,
|
||||
@@ -52,14 +48,19 @@ fun Navhost(
|
||||
) {
|
||||
|
||||
|
||||
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.AllDishes.route) { DishList(navController, userUid = userUid) }
|
||||
composable(Screen.FavoriteDishes.route) { DishList(navController, userUid = userUid, typeDishList = TypeDishList.FavoritesDishes) }
|
||||
composable(Screen.UserPage.route) { UserView(navController, userUid = userUid) }
|
||||
|
||||
composable(Screen.DishView.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) { backStackEntry ->
|
||||
backStackEntry.arguments?.let { DishView(it.getInt("id")) }
|
||||
backStackEntry.arguments?.let { DishView(navController, userUid = userUid, dishUid = it.getInt("id")) }
|
||||
}
|
||||
composable(Screen.DishEdit.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||
) {
|
||||
DishEditView(navController = navController, userUid=userUid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ 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.Info
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.example.myapplication.R
|
||||
|
||||
@@ -19,14 +18,16 @@ enum class Screen(
|
||||
AllDishes("all-dishes", R.string.all_dishes, icon_id = R.drawable.cooking_book),
|
||||
DishView("dish/{id}", R.string.all_dishes, icon=Icons.Filled.Info),
|
||||
FavoriteDishes("favorite-dishes", R.string.favorite_dishes, icon=Icons.Filled.Favorite),
|
||||
UserPage("user", R.string.account_title, icon=Icons.Filled.AccountCircle);
|
||||
UserPage("user", R.string.account_title, icon=Icons.Filled.AccountCircle),
|
||||
DishEdit("dish-edit/{id}", R.string.all_dishes);
|
||||
|
||||
|
||||
|
||||
companion object {
|
||||
val navbarItems = listOf(
|
||||
FavoriteDishes,
|
||||
AllDishes,
|
||||
UserPage
|
||||
UserPage,
|
||||
)
|
||||
|
||||
fun getItem(route: String): Screen? {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.example.myapplication.ui.user
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.AppViewModelProvider
|
||||
//import com.example.myapplication.Dishes.Model.getAllDishes
|
||||
import com.example.myapplication.ui.dishes.list.DishList
|
||||
import com.example.myapplication.database.model.User
|
||||
import com.example.myapplication.ui.dishes.list.TypeDishList
|
||||
import com.example.myapplication.ui.extra.ErrorElement
|
||||
import com.example.myapplication.ui.extra.ErrorsType
|
||||
import com.example.myapplication.ui.navigation.Screen
|
||||
//import com.example.myapplication.User.Model.getAllUsers
|
||||
import com.example.myapplication.ui.theme.textFont
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun UserView (
|
||||
navController: NavController,
|
||||
viewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
userUid: Int?
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val userUiState by viewModel.getUser(userUid ?: 0).collectAsState()
|
||||
|
||||
Scaffold(
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
val route = Screen.DishEdit.route.replace("{id}", 0.toString())
|
||||
navController.navigate(route)
|
||||
},
|
||||
) {
|
||||
Icon(Icons.Filled.Add, "Добавить")
|
||||
}
|
||||
}
|
||||
) {innerPadding ->
|
||||
if (userUiState.user == null) {
|
||||
ErrorElement(navController = navController, typeErrorsType = ErrorsType.NOT_AUTH)
|
||||
}
|
||||
else {
|
||||
UserView(
|
||||
navController = navController,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
user = userUiState.user!!
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
@Composable
|
||||
private fun UserView(
|
||||
navController: NavController,
|
||||
modifier: Modifier,
|
||||
user: User
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp, horizontal = 10.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
|
||||
Column {
|
||||
Text(user.nickname, fontFamily= textFont,
|
||||
fontSize=26.sp, textAlign = TextAlign.Start)
|
||||
}
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
DishList(navController, userUid = user.uid, typeDishList = TypeDishList.UserDishes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.example.myapplication.ui.user
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.myapplication.database.AppDataContainer
|
||||
import com.example.myapplication.database.model.Dish
|
||||
import com.example.myapplication.database.model.User
|
||||
import com.example.myapplication.database.repository.DishRepository
|
||||
import com.example.myapplication.database.repository.UserRepository
|
||||
import com.example.myapplication.database.repository.UserWithFavoritesRepository
|
||||
import com.example.myapplication.ui.dishes.list.DishListUiState
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
class UserViewModel(
|
||||
private val userRepository: UserRepository,
|
||||
) : ViewModel() {
|
||||
fun getUser(uid: Int) : StateFlow<UserUiState> {
|
||||
return userRepository.getUser(uid).map {
|
||||
UserUiState(it!!)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
|
||||
initialValue = UserUiState()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class UserUiState(val user: User? = null)
|
||||
@@ -10,7 +10,9 @@ Quisque efficitur, nunc vitae varius faucibus, turpis nunc ullamcorper neque, in
|
||||
Donec molestie scelerisque sollicitudin. Duis orci felis, lacinia laoreet scelerisque sed, molestie sed ipsum. Duis auctor aliquet laoreet. Mauris vitae commodo nibh. Sed pulvinar metus lacus, a faucibus nulla ornare ultricies. Aliquam varius sem a nibh dapibus congue. Phasellus dignissim nibh diam. Etiam elit nulla, bibendum ac quam sed, dictum condimentum ligula.
|
||||
Phasellus eget ex sed tortor placerat suscipit quis quis magna. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean mi quam, auctor quis ante nec, condimentum maximus justo. Morbi varius est massa. Integer nec semper mi. Fusce nisl neque, mollis quis tempus eget, vulputate vitae sem. Donec sit amet maximus augue. Quisque sit amet ante fermentum, bibendum mi ut, porta eros. Phasellus ultrices, augue a fringilla accumsan, elit arcu vehicula lectus, condimentum malesuada lectus enim nec tellus. Nunc ante erat, convallis a dui vitae, rhoncus rhoncus metus. Suspendisse in sapien odio.
|
||||
Cras semper magna id libero gravida, at varius elit molestie. Quisque ullamcorper nisi tincidunt, feugiat justo nec, aliquam massa. Quisque sit amet quam semper, pretium justo non, tincidunt lorem. Proin rhoncus turpis orci, efficitur dignissim ex sollicitudin eget. Etiam porttitor est eget erat pellentesque, ut maximus mi dictum. Pellentesque ac mauris non eros mollis pharetra et eu augue. Nam a bibendum ipsum, vel pellentesque nisi. Nam gravida dolor sed risus ornare dignissim. Praesent semper, tellus sed posuere efficitur, neque justo efficitur dui, et mollis leo ex in quam. Fusce pulvinar turpis a justo pretium semper. Integer dapibus, risus vel facilisis porttitor, eros sapien venenatis risus, eget aliquet lectus ipsum a orci. Ut at arcu a augue varius gravida non sit amet quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nullam eget enim eu mauris rutrum pulvinar.
|
||||
|
||||
|
||||
</string>
|
||||
<string name="dish_label">Name of dish</string>
|
||||
<string name="dish_description">Description</string>
|
||||
<string name="dish_save">Save</string>
|
||||
<string name="category_not_found">Choose category</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user