diff --git a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeLocalDataSource.kt b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeLocalDataSource.kt index d9d5f79d..5f97ca41 100644 --- a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeLocalDataSource.kt +++ b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/DefaultMakingRecipeLocalDataSource.kt @@ -26,12 +26,12 @@ class DefaultMakingRecipeLocalDataSource override suspend fun saveRecipeDescription( recipeDescription: RecipeDescriptionEntity, ingredients: List, - categories: List, + category: CategoryEntity, ): Long { return database.withTransaction { recipeDescriptionDao.insertCreatedRecipeDescription(recipeDescription) ingredientDao.saveIngredients(ingredients) - categoryDao.saveCategories(categories) + categoryDao.saveSingleCategory(category) recipeDescription.id } } diff --git a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeLocalDataSource.kt b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeLocalDataSource.kt index c944c3ef..62878839 100644 --- a/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeLocalDataSource.kt +++ b/android/app/src/main/java/net/pengcook/android/data/datasource/makingrecipe/MakingRecipeLocalDataSource.kt @@ -10,7 +10,7 @@ interface MakingRecipeLocalDataSource { suspend fun saveRecipeDescription( recipeDescription: RecipeDescriptionEntity, ingredients: List, - categories: List, + category: CategoryEntity, ): Long suspend fun fetchTotalRecipeData(): CreatedRecipe? diff --git a/android/app/src/main/java/net/pengcook/android/data/local/database/RecipeDatabase.kt b/android/app/src/main/java/net/pengcook/android/data/local/database/RecipeDatabase.kt index 75e1a210..4e0ecda3 100644 --- a/android/app/src/main/java/net/pengcook/android/data/local/database/RecipeDatabase.kt +++ b/android/app/src/main/java/net/pengcook/android/data/local/database/RecipeDatabase.kt @@ -15,7 +15,7 @@ import net.pengcook.android.data.model.step.RecipeStepEntity @Database( entities = [RecipeDescriptionEntity::class, RecipeStepEntity::class, CategoryEntity::class, IngredientEntity::class], - version = 5, + version = 6, ) abstract class RecipeDatabase : RoomDatabase() { abstract fun recipeDescriptionDao(): RecipeDescriptionDao diff --git a/android/app/src/main/java/net/pengcook/android/data/model/makingrecipe/entity/CategoryEntity.kt b/android/app/src/main/java/net/pengcook/android/data/model/makingrecipe/entity/CategoryEntity.kt index 7f54611a..239b9aa1 100644 --- a/android/app/src/main/java/net/pengcook/android/data/model/makingrecipe/entity/CategoryEntity.kt +++ b/android/app/src/main/java/net/pengcook/android/data/model/makingrecipe/entity/CategoryEntity.kt @@ -19,7 +19,7 @@ import net.pengcook.android.data.local.database.contract.RecipeDescriptionContra ], ) data class CategoryEntity( - @PrimaryKey(autoGenerate = false) + @PrimaryKey(autoGenerate = true) @ColumnInfo(CategoryContract.COLUMN_ID) val id: Long = 0, @ColumnInfo(CategoryContract.COLUMN_RECIPE_DESCRIPTION_ID) val recipeId: Long, @ColumnInfo(CategoryContract.COLUMN_CATEGORY_NAME) val categoryName: String, diff --git a/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/DefaultMakingRecipeRepository.kt b/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/DefaultMakingRecipeRepository.kt index 3256cb56..08e7a629 100644 --- a/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/DefaultMakingRecipeRepository.kt +++ b/android/app/src/main/java/net/pengcook/android/data/repository/makingrecipe/DefaultMakingRecipeRepository.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.launch import net.pengcook.android.data.datasource.auth.SessionLocalDataSource import net.pengcook.android.data.datasource.makingrecipe.MakingRecipeLocalDataSource import net.pengcook.android.data.datasource.makingrecipe.MakingRecipeRemoteDataSource -import net.pengcook.android.data.util.mapper.toCategoryEntities +import net.pengcook.android.data.model.makingrecipe.entity.CategoryEntity import net.pengcook.android.data.util.mapper.toIngredientEntities import net.pengcook.android.data.util.mapper.toRecipeCreation import net.pengcook.android.data.util.mapper.toRecipeCreationRequest @@ -40,7 +40,9 @@ class DefaultMakingRecipeRepository override suspend fun fetchTotalRecipeData(): Result = runCatching { - makingRecipeLocalDataSource.fetchTotalRecipeData()?.toRecipeCreation() + val recipeCreation = makingRecipeLocalDataSource.fetchTotalRecipeData()?.toRecipeCreation() + println(recipeCreation) + recipeCreation } override suspend fun fetchRecipeDescription(): Result = @@ -52,12 +54,13 @@ class DefaultMakingRecipeRepository runCatching { val id = recipeDescription.recipeDescriptionId val recipeDescriptionEntity = recipeDescription.toRecipeDescriptionEntity(id) - val categoryEntities = recipeDescription.categories.toCategoryEntities(id) +// val categoryEntities = recipeDescription.categories.toCategoryEntities(id) + val categoryEntity = CategoryEntity(recipeId = id, categoryName = recipeDescription.categories.joinToString()) val ingredientEntities = recipeDescription.ingredients.toIngredientEntities(id) makingRecipeLocalDataSource.saveRecipeDescription( recipeDescription = recipeDescriptionEntity, ingredients = ingredientEntities, - categories = categoryEntities, + category = categoryEntity, ) } diff --git a/android/app/src/main/java/net/pengcook/android/data/util/mapper/RecipeMakingMapper.kt b/android/app/src/main/java/net/pengcook/android/data/util/mapper/RecipeMakingMapper.kt index 57439d71..18a44f87 100644 --- a/android/app/src/main/java/net/pengcook/android/data/util/mapper/RecipeMakingMapper.kt +++ b/android/app/src/main/java/net/pengcook/android/data/util/mapper/RecipeMakingMapper.kt @@ -48,7 +48,7 @@ fun CreatedRecipe.toRecipeCreation(): RecipeCreation = cookingTime = recipeDescription.cookingTime, difficulty = recipeDescription.difficulty, ingredients = ingredients.map { it.toIngredient() }, - categories = categories.map { it.categoryName }, + categories = categories.first().categoryName.split(",").map(String::trim), thumbnail = recipeDescription.thumbnail, steps = steps.map { it.toRecipeStepMaking() }, ) diff --git a/android/app/src/main/java/net/pengcook/android/presentation/category/CategoryFragment.kt b/android/app/src/main/java/net/pengcook/android/presentation/category/CategoryFragment.kt index d610dd88..5673ff9c 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/category/CategoryFragment.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/category/CategoryFragment.kt @@ -7,10 +7,10 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.GridLayoutManager import dagger.hilt.android.AndroidEntryPoint import net.pengcook.android.R import net.pengcook.android.databinding.FragmentCategoryBinding -import net.pengcook.android.presentation.core.style.GridSpacingItemDecoration import net.pengcook.android.presentation.core.util.AnalyticsLogging @AndroidEntryPoint @@ -37,11 +37,28 @@ class CategoryFragment : Fragment() { super.onViewCreated(view, savedInstanceState) AnalyticsLogging.init(requireContext()) // Firebase Analytics 초기화 AnalyticsLogging.viewLogEvent("Category") - binding.adapter = adapter + initializeAdapter() setUpCategories() observeEvents() } + private fun initializeAdapter() { + binding.adapter = adapter + val layoutManager = GridLayoutManager(requireContext(), 3) + binding.rvCategory.layoutManager = + layoutManager.apply { + spanSizeLookup = + object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return when (position) { + 0 -> 3 + else -> 1 + } + } + } + } + } + override fun onDestroyView() { super.onDestroyView() _binding = null @@ -65,53 +82,33 @@ class CategoryFragment : Fragment() { private fun setUpCategories() { val categories = categories() adapter.submitList(categories) - val spacingInPixels = resources.getDimensionPixelSize(R.dimen.item_spacing_category) - binding.rvCategory.addItemDecoration(GridSpacingItemDecoration(3, spacingInPixels)) } private fun categories() = listOf( Category( - 1, - "Belgian", - "https://www.starttravel.co.uk/media/images/84310b25-c298-444e-8695-5ee4830e1e79.png", - "Belgian", - ), - Category( - 2, - "French", - "https://admin.expatica.com/fr/wp-content/uploads/sites/5/2023/11/french-food-1536x1024.jpg", - "French", - ), - Category( - 3, - "German", - "https://admin.expatica.com/de/wp-content/uploads/sites/6/2023/11/bratwurst-sauerkraut.jpg", - "German", + id = 100, + title = getString(R.string.category_culinary_classwars), + imageUrl = "https://github.com/user-attachments/assets/81327a0a-715d-4c91-b570-43c3386d1866", + code = "흑백요리사", ), Category( - 4, - "Indonesian", - "https://tasteofbali.ro/wp-content/uploads/2023/02/asian_food_Taste_of_Bali-1024x682.jpg", - "Indonesian", - ), - Category( - 5, - "Seafood", - "https://cdn11.bigcommerce.com/s-iz8lky8j1x/product_images/uploaded_images/istock-520490716.jpg", - "Seafood", + 1, + getString(R.string.category_korean), + "https://www.90daykorean.com/wp-content/uploads/2015/04/bigstock-Bibimbap-On-A-Concrete-Backgro-449450285-1024x683.jpg", + "Korean", ), Category( - 6, - "Japanese", + 2, + getString(R.string.category_japanese), "https://railrocker.com/playground/wp-content/uploads/2020/02/Onigiri-traditional-Japanese-Rice-Balls.jpg", "Japanese", ), Category( - 7, - "Korean", - "https://www.90daykorean.com/wp-content/uploads/2015/04/bigstock-Bibimbap-On-A-Concrete-Backgro-449450285-1024x683.jpg", - "Korean", + 3, + getString(R.string.category_chinese), + "https://image.yes24.com/images/chyes24/0/a/3/7/0a379fd46d1e404ed63adc3beee52b33.jpg", + "Chinese", ), ) } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt index 039e5b1c..6e103346 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingFragment.kt @@ -7,7 +7,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ArrayAdapter import androidx.activity.result.contract.ActivityResultContracts import androidx.datastore.core.IOException import androidx.fragment.app.Fragment @@ -108,7 +107,7 @@ class RecipeMakingFragment : Fragment() { initBinding() initTimeFormatInput() observeUiEvent() - setUpCategorySpinner() +// setUpCategorySpinner() } override fun onDestroyView() { @@ -209,16 +208,16 @@ class RecipeMakingFragment : Fragment() { } } - private fun setUpCategorySpinner() { - val countryAdapter = - ArrayAdapter( - requireContext(), - android.R.layout.simple_spinner_item, - resources.getStringArray(R.array.signup_countries), - ) - countryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - binding.makingRecipeCategory.spFormContent.spDefault.adapter = countryAdapter - } +// private fun setUpCategorySpinner() { +// val countryAdapter = +// ArrayAdapter( +// requireContext(), +// android.R.layout.simple_spinner_item, +// resources.getStringArray(R.array.signup_countries), +// ) +// countryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) +// binding.makingRecipeCategory.spFormContent.spDefault.adapter = countryAdapter +// } private fun showSnackBar(message: String) { Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show() diff --git a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt index 5ea6707c..8baf3c86 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/making/RecipeMakingViewModel.kt @@ -10,7 +10,6 @@ import kotlinx.coroutines.launch import net.pengcook.android.data.repository.makingrecipe.MakingRecipeRepository import net.pengcook.android.domain.model.recipemaking.RecipeDescription import net.pengcook.android.presentation.core.listener.AppbarSingleActionEventListener -import net.pengcook.android.presentation.core.listener.SpinnerItemChangeListener import net.pengcook.android.presentation.core.util.Event import net.pengcook.android.presentation.making.listener.RecipeMakingEventListener import java.io.File @@ -24,16 +23,12 @@ class RecipeMakingViewModel private val makingRecipeRepository: MakingRecipeRepository, ) : ViewModel(), RecipeMakingEventListener, - SpinnerItemChangeListener, AppbarSingleActionEventListener { private val _uiEvent: MutableLiveData> = MutableLiveData() val uiEvent: LiveData> get() = _uiEvent - private val _categorySelectedValue: MutableLiveData = MutableLiveData() - val categorySelectedValue: LiveData - get() = _categorySelectedValue - + val categoryContent = MutableLiveData() val titleContent = MutableLiveData() val ingredientContent = MutableLiveData() val difficultySelectedValue = MutableLiveData(0.0f) @@ -106,7 +101,7 @@ class RecipeMakingViewModel override fun onConfirm() { viewModelScope.launch { - val category = categorySelectedValue.value?.trim() + val category = categoryContent.value?.trim() val introduction = introductionContent.value?.trim() val difficulty = difficultySelectedValue.value val ingredients = ingredientContent.value?.trim() @@ -146,10 +141,6 @@ class RecipeMakingViewModel } } - override fun onSelectionChange(item: String) { - _categorySelectedValue.value = item - } - override fun onNavigateBack() { _uiEvent.value = Event(RecipeMakingEvent.MakingCancellation) } @@ -182,7 +173,7 @@ class RecipeMakingViewModel thumbnailTitle = existingRecipe.thumbnail _imageUploaded.value = true _imageSelected.value = true - _categorySelectedValue.value = existingRecipe.categories.first() + categoryContent.value = existingRecipe.categories.joinToString() _currentImage.value = Uri.parse(existingRecipe.imageUri) } @@ -197,7 +188,7 @@ class RecipeMakingViewModel val recipeDescription = RecipeDescription( recipeDescriptionId = recipeId ?: return, - categories = listOf(category), + categories = category.split(SEPARATOR_INGREDIENTS).map { it.trim() }, cookingTime = timeRequired, description = introduction, difficulty = (difficulty * 2).toInt(), @@ -212,6 +203,7 @@ class RecipeMakingViewModel .onSuccess { recipeId -> _uiEvent.value = Event(RecipeMakingEvent.NavigateToMakingStep(recipeId)) }.onFailure { + println(it.message) _uiEvent.value = Event(RecipeMakingEvent.PostRecipeFailure) } } diff --git a/android/app/src/main/java/net/pengcook/android/presentation/search/SearchViewModel.kt b/android/app/src/main/java/net/pengcook/android/presentation/search/SearchViewModel.kt index 4d2a889e..75790be0 100644 --- a/android/app/src/main/java/net/pengcook/android/presentation/search/SearchViewModel.kt +++ b/android/app/src/main/java/net/pengcook/android/presentation/search/SearchViewModel.kt @@ -62,7 +62,8 @@ class SearchViewModel ): Boolean = keyword.isEmpty() || recipe.title.contains(keyword, ignoreCase = true) || - recipe.introduction.contains(keyword, ignoreCase = true) + recipe.introduction.contains(keyword, ignoreCase = true) || + recipe.category.joinToString().contains(keyword, ignoreCase = true) companion object { private const val INITIAL_KEYWORD = "" diff --git a/android/app/src/main/res/layout/fragment_category.xml b/android/app/src/main/res/layout/fragment_category.xml index 92460974..83d59ea3 100644 --- a/android/app/src/main/res/layout/fragment_category.xml +++ b/android/app/src/main/res/layout/fragment_category.xml @@ -27,9 +27,7 @@ android:layout_width="match_parent" android:layout_height="0dp" android:adapter="@{adapter}" - app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layout_behavior="@string/appbar_scrolling_view_behavior" - app:spanCount="3" tools:listitem="@layout/item_category" app:layout_constraintTop_toBottomOf="@id/abl_category" app:layout_constraintBottom_toBottomOf="parent" diff --git a/android/app/src/main/res/layout/fragment_detail_recipe.xml b/android/app/src/main/res/layout/fragment_detail_recipe.xml index 73365e80..faa98ff8 100644 --- a/android/app/src/main/res/layout/fragment_detail_recipe.xml +++ b/android/app/src/main/res/layout/fragment_detail_recipe.xml @@ -226,7 +226,7 @@ android:id="@+id/tv_ingredients_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Ingredients" + android:text="@string/making_form_ingredient" android:textColor="@color/black" android:textSize="16sp" android:textStyle="bold" @@ -249,7 +249,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" - android:text="Time Required" + android:text="@string/making_form_time_required" android:textColor="@color/black" android:textSize="16sp" android:textStyle="bold" @@ -272,7 +272,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" - android:text="Difficulty" + android:text="@string/making_form_difficulty" android:textColor="@color/black" android:textSize="16sp" android:textStyle="bold" @@ -295,7 +295,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" - android:text="Introduction" + android:text="@string/making_form_introduction" android:textColor="@color/black" android:textSize="16sp" android:textStyle="bold" @@ -321,7 +321,7 @@ android:background="@drawable/shape_button_round_corner" android:gravity="center" android:onClick="@{() -> vm.onNavigateToMakingStep()}" - android:text="Start" + android:text="@string/detail_start" android:textColor="@color/black" android:textSize="20sp" android:textStyle="bold" @@ -361,40 +361,8 @@ app:layout_constraintTop_toTopOf="parent" tools:text="Comments 12" /> - - - - - - - diff --git a/android/app/src/main/res/layout/fragment_recipe_making.xml b/android/app/src/main/res/layout/fragment_recipe_making.xml index 8ce2fde5..5a530ce9 100644 --- a/android/app/src/main/res/layout/fragment_recipe_making.xml +++ b/android/app/src/main/res/layout/fragment_recipe_making.xml @@ -67,16 +67,17 @@ + app:title="@{@string/making_form_category}" /> + + PengCook + hello world + + %d like + %,d likes + + %d mins + + + PengCook + 요리를 쉽게! 나만의 레시피! + 구글로 로그인하기 + + 회원가입 시, <a href="https://pengcook.net/terms-of-service"><u>이용 약관</u></a>과 <a href="https://pengcook.net/privacy-policy"><u>개인정보 처리방침</u></a>에<br/> 동의하는 것으로 간주합니다. + + logo + 예상치 못한 오류가 발생했습니다. + Failed action + 회원 가입 + 유저명 + 유저명을 입력하세요. + 닉네임 + 닉네임을 입력하세요. + 생년월일 + 국가 + 다음 + 유저명은 2 ~ 30자 사이로 입력해야 합니다. + 유저명이 이미 존재합니다. + 입력되지 않은 폼이 있습니다. + 닉네임은 1 ~ 30자 사이로 입력해야 합니다. + 서버 오류가 발생했습니다. + + Belgian + Chinese + German + French + Indian + Indonesian + Italian + Japanese + Korean + Turkish + Thai + Vietnam + + + 흑백요리사 + 한식 + 일식 + 중식 + + 레시피 명을 작성해주세요 + + 카테고리 + + 검색 + 검색어를 입력하세요. + 검색 중 오류가 발생했습니다. + + 레시피 스텝을 작성해주세요. + 스텝 + step %s + 레시피 개요 + 레시피 제목 + 카테고리 + 재료 + 소요 시간 + 난이도 + 소개글 + + 레시피 제목을 작성해주세요. + 재료를 작성해주세요. + 레시피 소개글을 작성해주세요. + 예) 흑백요리사, 한식 + 다음 + 스텝 작성하기 + 다음 스텝 + + 이미지 로딩 중... + 이전 + 카메라 권한이 허용되었습니다. + 카메라 권한이 필요합니다. + 이미지 선택에 실패하였습니다. + 사진 촬영에 실패하였습니다. + 이미지가 성공적으로 업로드 되었습니다. + 이미지 업로드가 실패하였습니다. + 이미지 소스를 선택해주세요. + 카메라로 가져오기 + 앨범에서 가져오기 + + %,d followers ・ %,d recipes + 프로필 + 프로필 수정 + 설정 + 제거 + 언팔로우 + 검색 + + 설정 + 좋아요 + 댓글 목록 + 차단한 사용자 + 언어 + 개인정보 처리방침 + 이용약관 + 계정 관리 + 계정 관리 + 프로필 수정 + 저장하기 + 입력되지 않은 폼이 있습니다. + 레시피 전송이 실패하였습니다. + 팔로잉 + + 댓글 + 댓글이 없습니다. + 댓글 + 댓글이 없습니다 + 댓글 %d + 댓글 %,d + + 레시피 개요 + 시작하기 + %d Comment + %,d Comments + 로그아웃 + 회원탈퇴 + + 레시피 스텝 + + 유저 %s가 신고되었습니다. + 댓글이 삭제되었습니다. + + 신고 사유를 선택해주세요. + 신고 사유를 선택해주세요. + 신고가 완료되었습니다. + 완료되지 않은 폼이 있습니다. + Comments + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 6aa9a47b..04d67af6 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -67,6 +67,7 @@ Write Recipe Title Write Ingredient + Write Categories Write Recipe Introduction Next Make Recipe Step @@ -115,6 +116,7 @@ Comments %,d Description + Start %d Comment %,d Comments Sign out @@ -130,6 +132,10 @@ Recipe Report Success Please fill this form Comments + Culinary Class Wars + Korean + Japanese + Chinese