From 756cfa14c01488f732b3c5b5ed1b6c4324787149 Mon Sep 17 00:00:00 2001 From: shadowik Date: Thu, 23 Nov 2023 06:11:47 +0400 Subject: [PATCH] 4 Lab Recover Old Functional --- app/src/main/AndroidManifest.xml | 1 + .../myapplication/AppViewModelProvider.kt | 32 +++ .../myapplication/Dishes/ui/DishList.kt | 195 ---------------- .../myapplication/FoodWarriorsApplication.kt | 14 ++ .../myapplication/database/AppContainer.kt | 42 ++++ .../myapplication/database/AppDatabase.kt | 17 +- .../{Dishes => database}/dao/CategoryDao.kt | 7 +- .../{Dishes => database}/dao/DishDao.kt | 8 +- .../{User => database}/dao/UserDao.kt | 9 +- .../dao/UserFavoritesDao.kt | 12 +- .../Model => database/model}/Category.kt | 2 +- .../{Dishes/Model => database/model}/Dish.kt | 5 +- .../model}/DishWithCategoryAndUser.kt | 2 +- .../{User/Model => database/model}/User.kt | 3 +- .../Model => database/model}/UserFavorites.kt | 5 +- .../model}/UserWithFavorites.kt | 7 +- .../database/repository/CategoryRepository.kt | 8 + .../database/repository/DishRepository.kt | 15 ++ .../repository/OfflineCategoryRepository.kt | 11 + .../repository/OfflineDishRepository.kt | 32 +++ .../OfflineUserFavoritesRepository.kt | 24 ++ .../repository/OfflineUserRepository.kt | 27 +++ .../database/repository/UserRepository.kt | 12 + .../repository/UserWithFavoritesRepository.kt | 15 ++ .../myapplication/ui/dishes/list/DishList.kt | 208 ++++++++++++++++++ .../ui/dishes/list/DishListViewModel.kt | 69 ++++++ .../{Dishes/ui => ui/dishes/view}/DishView.kt | 87 +++++--- .../ui/dishes/view/DishViewModel.kt | 29 +++ .../example/myapplication/ui/extra/Errors.kt | 43 ++++ .../myapplication/ui/extra/ErrorsViewModel.kt | 27 +++ .../myapplication/ui/navigation/MainNavbar.kt | 29 +-- .../{User/ui => ui/user}/UserView.kt | 84 ++++--- .../myapplication/ui/user/UserViewModel.kt | 31 +++ 33 files changed, 785 insertions(+), 327 deletions(-) create mode 100644 app/src/main/java/com/example/myapplication/AppViewModelProvider.kt delete mode 100644 app/src/main/java/com/example/myapplication/Dishes/ui/DishList.kt create mode 100644 app/src/main/java/com/example/myapplication/FoodWarriorsApplication.kt create mode 100644 app/src/main/java/com/example/myapplication/database/AppContainer.kt rename app/src/main/java/com/example/myapplication/{Dishes => database}/dao/CategoryDao.kt (69%) rename app/src/main/java/com/example/myapplication/{Dishes => database}/dao/DishDao.kt (76%) rename app/src/main/java/com/example/myapplication/{User => database}/dao/UserDao.kt (75%) rename app/src/main/java/com/example/myapplication/{User => database}/dao/UserFavoritesDao.kt (63%) rename app/src/main/java/com/example/myapplication/{Dishes/Model => database/model}/Category.kt (96%) rename app/src/main/java/com/example/myapplication/{Dishes/Model => database/model}/Dish.kt (92%) rename app/src/main/java/com/example/myapplication/{Dishes/Model => database/model}/DishWithCategoryAndUser.kt (84%) rename app/src/main/java/com/example/myapplication/{User/Model => database/model}/User.kt (92%) rename app/src/main/java/com/example/myapplication/{User/Model => database/model}/UserFavorites.kt (71%) rename app/src/main/java/com/example/myapplication/{User/Model => database/model}/UserWithFavorites.kt (72%) create mode 100644 app/src/main/java/com/example/myapplication/database/repository/CategoryRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/database/repository/DishRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/database/repository/OfflineCategoryRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/database/repository/OfflineDishRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/database/repository/OfflineUserFavoritesRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/database/repository/OfflineUserRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/database/repository/UserRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/database/repository/UserWithFavoritesRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/ui/dishes/list/DishList.kt create mode 100644 app/src/main/java/com/example/myapplication/ui/dishes/list/DishListViewModel.kt rename app/src/main/java/com/example/myapplication/{Dishes/ui => ui/dishes/view}/DishView.kt (61%) create mode 100644 app/src/main/java/com/example/myapplication/ui/dishes/view/DishViewModel.kt create mode 100644 app/src/main/java/com/example/myapplication/ui/extra/Errors.kt create mode 100644 app/src/main/java/com/example/myapplication/ui/extra/ErrorsViewModel.kt rename app/src/main/java/com/example/myapplication/{User/ui => ui/user}/UserView.kt (51%) create mode 100644 app/src/main/java/com/example/myapplication/ui/user/UserViewModel.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e013846..a12c956 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> () } - val favoriteDishes = remember { mutableStateListOf() } - 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) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/FoodWarriorsApplication.kt b/app/src/main/java/com/example/myapplication/FoodWarriorsApplication.kt new file mode 100644 index 0000000..870e513 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/FoodWarriorsApplication.kt @@ -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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/AppContainer.kt b/app/src/main/java/com/example/myapplication/database/AppContainer.kt new file mode 100644 index 0000000..fb158cb --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/AppContainer.kt @@ -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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/AppDatabase.kt b/app/src/main/java/com/example/myapplication/database/AppDatabase.kt index bfb9cd5..1c575f2 100644 --- a/app/src/main/java/com/example/myapplication/database/AppDatabase.kt +++ b/app/src/main/java/com/example/myapplication/database/AppDatabase.kt @@ -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 diff --git a/app/src/main/java/com/example/myapplication/Dishes/dao/CategoryDao.kt b/app/src/main/java/com/example/myapplication/database/dao/CategoryDao.kt similarity index 69% rename from app/src/main/java/com/example/myapplication/Dishes/dao/CategoryDao.kt rename to app/src/main/java/com/example/myapplication/database/dao/CategoryDao.kt index b68a997..fa43932 100644 --- a/app/src/main/java/com/example/myapplication/Dishes/dao/CategoryDao.kt +++ b/app/src/main/java/com/example/myapplication/database/dao/CategoryDao.kt @@ -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 + fun getAll(): Flow> @Insert suspend fun insert(category: Category) diff --git a/app/src/main/java/com/example/myapplication/Dishes/dao/DishDao.kt b/app/src/main/java/com/example/myapplication/database/dao/DishDao.kt similarity index 76% rename from app/src/main/java/com/example/myapplication/Dishes/dao/DishDao.kt rename to app/src/main/java/com/example/myapplication/database/dao/DishDao.kt index 4691ec4..171ab27 100644 --- a/app/src/main/java/com/example/myapplication/Dishes/dao/DishDao.kt +++ b/app/src/main/java/com/example/myapplication/database/dao/DishDao.kt @@ -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 @Query("select * from dishes where dishes.user_id = :uid") fun getAllOFUser(uid: Int): Flow> diff --git a/app/src/main/java/com/example/myapplication/User/dao/UserDao.kt b/app/src/main/java/com/example/myapplication/database/dao/UserDao.kt similarity index 75% rename from app/src/main/java/com/example/myapplication/User/dao/UserDao.kt rename to app/src/main/java/com/example/myapplication/database/dao/UserDao.kt index 5828ac9..c2b1fe0 100644 --- a/app/src/main/java/com/example/myapplication/User/dao/UserDao.kt +++ b/app/src/main/java/com/example/myapplication/database/dao/UserDao.kt @@ -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> @Query("select * from users where users.user_id = :uid") - suspend fun getByUid(uid: Int): User + fun getByUid(uid: Int): Flow @Query("select * from user_favorites left join users on user_favorites.user_id = users.user_id " + diff --git a/app/src/main/java/com/example/myapplication/User/dao/UserFavoritesDao.kt b/app/src/main/java/com/example/myapplication/database/dao/UserFavoritesDao.kt similarity index 63% rename from app/src/main/java/com/example/myapplication/User/dao/UserFavoritesDao.kt rename to app/src/main/java/com/example/myapplication/database/dao/UserFavoritesDao.kt index 9e2c584..8c135ed 100644 --- a/app/src/main/java/com/example/myapplication/User/dao/UserFavoritesDao.kt +++ b/app/src/main/java/com/example/myapplication/database/dao/UserFavoritesDao.kt @@ -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> + + @Transaction + @Query("SELECT * FROM user_favorites us WHERE us.user_id = :userUid AND us.dish_id = :dishUid") + fun getUserFavorite(userUid: Int?, dishUid: Int?): Flow } \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/Dishes/Model/Category.kt b/app/src/main/java/com/example/myapplication/database/model/Category.kt similarity index 96% rename from app/src/main/java/com/example/myapplication/Dishes/Model/Category.kt rename to app/src/main/java/com/example/myapplication/database/model/Category.kt index be5dbef..6c2aa3e 100644 --- a/app/src/main/java/com/example/myapplication/Dishes/Model/Category.kt +++ b/app/src/main/java/com/example/myapplication/database/model/Category.kt @@ -1,4 +1,4 @@ -package com.example.myapplication.Dishes.Model +package com.example.myapplication.database.model import androidx.room.ColumnInfo import androidx.room.Entity diff --git a/app/src/main/java/com/example/myapplication/Dishes/Model/Dish.kt b/app/src/main/java/com/example/myapplication/database/model/Dish.kt similarity index 92% rename from app/src/main/java/com/example/myapplication/Dishes/Model/Dish.kt rename to app/src/main/java/com/example/myapplication/database/model/Dish.kt index 5f7f530..f8148f1 100644 --- a/app/src/main/java/com/example/myapplication/Dishes/Model/Dish.kt +++ b/app/src/main/java/com/example/myapplication/database/model/Dish.kt @@ -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, diff --git a/app/src/main/java/com/example/myapplication/Dishes/Model/DishWithCategoryAndUser.kt b/app/src/main/java/com/example/myapplication/database/model/DishWithCategoryAndUser.kt similarity index 84% rename from app/src/main/java/com/example/myapplication/Dishes/Model/DishWithCategoryAndUser.kt rename to app/src/main/java/com/example/myapplication/database/model/DishWithCategoryAndUser.kt index c1b98ec..9aaf130 100644 --- a/app/src/main/java/com/example/myapplication/Dishes/Model/DishWithCategoryAndUser.kt +++ b/app/src/main/java/com/example/myapplication/database/model/DishWithCategoryAndUser.kt @@ -1,4 +1,4 @@ -package com.example.myapplication.Dishes.Model +package com.example.myapplication.database.model import androidx.room.ColumnInfo import androidx.room.Embedded diff --git a/app/src/main/java/com/example/myapplication/User/Model/User.kt b/app/src/main/java/com/example/myapplication/database/model/User.kt similarity index 92% rename from app/src/main/java/com/example/myapplication/User/Model/User.kt rename to app/src/main/java/com/example/myapplication/database/model/User.kt index a188528..5070f9a 100644 --- a/app/src/main/java/com/example/myapplication/User/Model/User.kt +++ b/app/src/main/java/com/example/myapplication/database/model/User.kt @@ -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 ( diff --git a/app/src/main/java/com/example/myapplication/User/Model/UserFavorites.kt b/app/src/main/java/com/example/myapplication/database/model/UserFavorites.kt similarity index 71% rename from app/src/main/java/com/example/myapplication/User/Model/UserFavorites.kt rename to app/src/main/java/com/example/myapplication/database/model/UserFavorites.kt index 8712010..4d851d5 100644 --- a/app/src/main/java/com/example/myapplication/User/Model/UserFavorites.kt +++ b/app/src/main/java/com/example/myapplication/database/model/UserFavorites.kt @@ -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( diff --git a/app/src/main/java/com/example/myapplication/User/Model/UserWithFavorites.kt b/app/src/main/java/com/example/myapplication/database/model/UserWithFavorites.kt similarity index 72% rename from app/src/main/java/com/example/myapplication/User/Model/UserWithFavorites.kt rename to app/src/main/java/com/example/myapplication/database/model/UserWithFavorites.kt index b32d84c..5745012 100644 --- a/app/src/main/java/com/example/myapplication/User/Model/UserWithFavorites.kt +++ b/app/src/main/java/com/example/myapplication/database/model/UserWithFavorites.kt @@ -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 diff --git a/app/src/main/java/com/example/myapplication/database/repository/CategoryRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/CategoryRepository.kt new file mode 100644 index 0000000..942ed09 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/CategoryRepository.kt @@ -0,0 +1,8 @@ +package com.example.myapplication.database.repository + +import com.example.myapplication.database.model.Category +import kotlinx.coroutines.flow.Flow + +interface CategoryRepository { + fun getAllCategories(): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/repository/DishRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/DishRepository.kt new file mode 100644 index 0000000..151f789 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/DishRepository.kt @@ -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> + fun getDish(uid: Int): Flow + + fun getUserDishes(userUid: Int) : Flow> + suspend fun insertDish(dish: Dish) + suspend fun updateDish(dish: Dish) + suspend fun deleteDish(dish: Dish) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/repository/OfflineCategoryRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/OfflineCategoryRepository.kt new file mode 100644 index 0000000..4c231f4 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/OfflineCategoryRepository.kt @@ -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 fun getAllCategories(): Flow> { + return categoryDao.getAll(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/repository/OfflineDishRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/OfflineDishRepository.kt new file mode 100644 index 0000000..c05248e --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/OfflineDishRepository.kt @@ -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> { + return dishDao.getAll() + } + + override fun getDish(uid: Int): Flow { + return dishDao.getByUid(uid) + } + + override fun getUserDishes(userUid: Int): Flow> { + 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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/repository/OfflineUserFavoritesRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/OfflineUserFavoritesRepository.kt new file mode 100644 index 0000000..5844cab --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/OfflineUserFavoritesRepository.kt @@ -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> { + return userFavoritesDao.getUserFavorites(userUid) + } + + override fun getUserFavorite(userUid: Int, dishUid: Int): Flow { + 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)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/repository/OfflineUserRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/OfflineUserRepository.kt new file mode 100644 index 0000000..13e0d8e --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/OfflineUserRepository.kt @@ -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> { + return userDao.getAll() + } + + override fun getUser(uid: Int): Flow { + 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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/repository/UserRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/UserRepository.kt new file mode 100644 index 0000000..4826f36 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/UserRepository.kt @@ -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> + fun getUser(uid: Int): Flow + suspend fun insertUser(user: User) + suspend fun updateUser(user: User) + suspend fun deleteUser(user: User) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/repository/UserWithFavoritesRepository.kt b/app/src/main/java/com/example/myapplication/database/repository/UserWithFavoritesRepository.kt new file mode 100644 index 0000000..72970e1 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/repository/UserWithFavoritesRepository.kt @@ -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> + + fun getUserFavorite(userUid: Int, dishUid: Int): Flow + + suspend fun deleteUserFavorites(userUid: Int, dishUid: Int) + + suspend fun insertUserFavorites(userUid: Int, dishUid: Int) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/dishes/list/DishList.kt b/app/src/main/java/com/example/myapplication/ui/dishes/list/DishList.kt new file mode 100644 index 0000000..8f90e19 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/dishes/list/DishList.kt @@ -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, + favorites: List, + 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, + 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) +// } +// } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/dishes/list/DishListViewModel.kt b/app/src/main/java/com/example/myapplication/ui/dishes/list/DishListViewModel.kt new file mode 100644 index 0000000..7c61a87 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/dishes/list/DishListViewModel.kt @@ -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 = dishRepository.getAllDishes().map { + DishListUiState(it) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT), + initialValue = DishListUiState() + ) + + fun dishFavorites(userUid: Int) : StateFlow { + return userWithFavoritesRepository.getUserFavorites(userUid).map { + DishListUiState(it) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT), + initialValue = DishListUiState() + ) + } + + fun userDishes(userUid: Int) : StateFlow { + 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 = listOf()) \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/Dishes/ui/DishView.kt b/app/src/main/java/com/example/myapplication/ui/dishes/view/DishView.kt similarity index 61% rename from app/src/main/java/com/example/myapplication/Dishes/ui/DishView.kt rename to app/src/main/java/com/example/myapplication/ui/dishes/view/DishView.kt index 9d75d5b..0a098d7 100644 --- a/app/src/main/java/com/example/myapplication/Dishes/ui/DishView.kt +++ b/app/src/main/java/com/example/myapplication/ui/dishes/view/DishView.kt @@ -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,86 @@ 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.material3.ExperimentalMaterial3Api 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.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( + + ){ 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 +104,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 +116,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, @@ -99,17 +127,4 @@ fun DishView(id: Int) { ) } } -} - -@RequiresApi(Build.VERSION_CODES.Q) -@Preview -@Composable -fun DishPreview() { - MyApplicationTheme { - Surface( - color = MaterialTheme.colorScheme.background - ) { - DishView(id = 0) - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/dishes/view/DishViewModel.kt b/app/src/main/java/com/example/myapplication/ui/dishes/view/DishViewModel.kt new file mode 100644 index 0000000..86af1bd --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/dishes/view/DishViewModel.kt @@ -0,0 +1,29 @@ +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.Dish +import com.example.myapplication.database.model.DishWithCategoryAndUser +import com.example.myapplication.database.repository.DishRepository +import com.example.myapplication.ui.user.UserUiState +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 { + return dishRepository.getDish(uid).map { + DishUiState(it!!) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT), + initialValue = DishUiState() + ) + } +} + +data class DishUiState(val dish: DishWithCategoryAndUser? = null) \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/extra/Errors.kt b/app/src/main/java/com/example/myapplication/ui/extra/Errors.kt new file mode 100644 index 0000000..e512b75 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/extra/Errors.kt @@ -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) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/extra/ErrorsViewModel.kt b/app/src/main/java/com/example/myapplication/ui/extra/ErrorsViewModel.kt new file mode 100644 index 0000000..5f1076d --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/extra/ErrorsViewModel.kt @@ -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 = "") \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/navigation/MainNavbar.kt b/app/src/main/java/com/example/myapplication/ui/navigation/MainNavbar.kt index c95744e..289ee54 100644 --- a/app/src/main/java/com/example/myapplication/ui/navigation/MainNavbar.kt +++ b/app/src/main/java/com/example/myapplication/ui/navigation/MainNavbar.kt @@ -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,15 @@ 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.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 +39,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 +47,14 @@ 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")) } } } } diff --git a/app/src/main/java/com/example/myapplication/User/ui/UserView.kt b/app/src/main/java/com/example/myapplication/ui/user/UserView.kt similarity index 51% rename from app/src/main/java/com/example/myapplication/User/ui/UserView.kt rename to app/src/main/java/com/example/myapplication/ui/user/UserView.kt index db59195..8153d83 100644 --- a/app/src/main/java/com/example/myapplication/User/ui/UserView.kt +++ b/app/src/main/java/com/example/myapplication/ui/user/UserView.kt @@ -1,38 +1,42 @@ -package com.example.myapplication.User.ui +package com.example.myapplication.ui.user 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.ExperimentalMaterial3Api 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.MutableState +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.rememberCoroutineScope 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.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController +import com.example.myapplication.AppViewModelProvider //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.ui.dishes.list.DishList +import com.example.myapplication.database.model.User import com.example.myapplication.database.AppDatabase +import com.example.myapplication.ui.dishes.list.DishListViewModel +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.User.Model.getAllUsers import com.example.myapplication.ui.theme.MyApplicationTheme import com.example.myapplication.ui.theme.textFont @@ -40,46 +44,54 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @RequiresApi(Build.VERSION_CODES.Q) +@OptIn(ExperimentalMaterial3Api::class) @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) +fun UserView ( + navController: NavController, + viewModel: UserViewModel = viewModel(factory = AppViewModelProvider.Factory), + userUid: Int? +) { + val coroutineScope = rememberCoroutineScope() + val userUiState by viewModel.getUser(userUid ?: 0).collectAsState() + + Scaffold( + + ) {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.value.nickname, fontFamily= textFont, + Text(user.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) + DishList(navController, userUid = user.uid, typeDishList = TypeDishList.UserDishes) } } } - -@RequiresApi(Build.VERSION_CODES.Q) -@Preview -@Composable -fun UserPreview() { - MyApplicationTheme { - Surface( - color = MaterialTheme.colorScheme.background - ) { - UserView(id = 0, null) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/user/UserViewModel.kt b/app/src/main/java/com/example/myapplication/ui/user/UserViewModel.kt new file mode 100644 index 0000000..8108f2d --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/user/UserViewModel.kt @@ -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 { + 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) \ No newline at end of file