Skip to content

Commit

Permalink
✨ apply viewpager to making recipe step
Browse files Browse the repository at this point in the history
  • Loading branch information
Hogu59 committed Oct 23, 2024
1 parent 08fea3e commit 46812d0
Show file tree
Hide file tree
Showing 21 changed files with 626 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ import net.pengcook.android.data.model.makingrecipe.entity.RecipeDescriptionEnti
],
)
data class RecipeStepEntity(
@ColumnInfo(RecipeStepContract.COLUMN_ID) val id: Long = System.currentTimeMillis(),
@ColumnInfo(RecipeStepContract.COLUMN_STEP_NUMBER) val stepNumber: Int,
@ColumnInfo(RecipeStepContract.COLUMN_ID) val id: Long = (System.currentTimeMillis().toString() + stepNumber.toString()).toLong(),
@ColumnInfo(RecipeStepContract.COLUMN_RECIPE_DESCRIPTION_ID) val recipeDescriptionId: Long,
@ColumnInfo(RecipeStepContract.COLUMN_IMAGE_URI) val imageUri: String?,
@ColumnInfo(RecipeStepContract.COLUMN_IMAGE_TITLE) val imageTitle: String?,
@ColumnInfo(RecipeStepContract.COLUMN_COOKING_TIME) val cookingTime: String?,
@ColumnInfo(RecipeStepContract.COLUMN_STEP_NUMBER) val stepNumber: Int,
@ColumnInfo(RecipeStepContract.COLUMN_DESCRIPTION) val description: String?,
@ColumnInfo(RecipeStepContract.COLUMN_IMAGE_UPLOADED) val imageUploaded: Boolean,
)
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ fun loadImage(
view: ImageView,
uri: Uri?,
) {
println("uri: $uri")
Glide
.with(view.context)
.load(uri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,21 @@ data class RecipeStepMaking(
"cookingTime must be in the format of HH:MM:SS"
}
}

val minute: String = if (cookingTime.split(":")[1] == "00") "" else cookingTime.split(":")[1]
val second: String = if (cookingTime.split(":")[2] == "00") "" else cookingTime.split(":")[2]

companion object {
val EMPTY =
RecipeStepMaking(
stepId = 0,
recipeId = 0,
description = "",
image = "",
sequence = 0,
imageUri = "",
cookingTime = "00:00:00",
imageUploaded = false,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.Manifest
import android.app.AlertDialog
import android.net.Uri
import android.os.Bundle
import android.text.InputFilter.LengthFilter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
Expand Down Expand Up @@ -163,6 +164,16 @@ class RecipeMakingFragment2 : Fragment() {
observeStepItems()
}

/* override fun onResume() {
super.onResume()
viewModel.initRecipeSteps()
}*/

override fun onStart() {
super.onStart()
viewModel.initRecipeSteps()
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
Expand All @@ -183,8 +194,8 @@ class RecipeMakingFragment2 : Fragment() {
val etHour = binding.itemTimeRequired.etTimeAmountPicker.etHour
val etMinute = binding.itemTimeRequired.etTimeAmountPicker.etMinute
val etSecond = binding.itemTimeRequired.etTimeAmountPicker.etSecond
etHour.filters = arrayOf(MinMaxInputFilter(0, 23))
arrayOf(MinMaxInputFilter(0, 59)).also { filters ->
etHour.filters = arrayOf(MinMaxInputFilter(0, 23), LengthFilter(2))
arrayOf(MinMaxInputFilter(0, 59), LengthFilter(2)).also { filters ->
etMinute.filters = filters
etSecond.filters = filters
}
Expand All @@ -193,9 +204,6 @@ class RecipeMakingFragment2 : Fragment() {
private fun observeStepItems() {
viewModel.currentStepImages.observe(viewLifecycleOwner) {
stepImageAdapter.submitList(it)
stepImageAdapter.currentList.forEach {
println("sequence : ${it.sequence}")
}
}
}

Expand Down Expand Up @@ -226,9 +234,9 @@ class RecipeMakingFragment2 : Fragment() {
is RecipeMakingEvent2.RecipePostFailure -> showSnackBar(getString(R.string.making_warning_post_failure))
is RecipeMakingEvent2.RecipePostSuccessful -> findNavController().navigateUp()
is RecipeMakingEvent2.NavigateToMakingStep -> {
val sequence = newEvent.sequence
val sequence: Int = newEvent.sequence
val action =
RecipeMakingFragment2Directions.actionRecipeMakingFragmentToStepMakingFragment(1L)
RecipeMakingFragment2Directions.actionRecipeMakingFragmentToStepMakingFragment(sequence)
findNavController().navigate(action)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ class RecipeMakingViewModel2

init {
initRecipeDescription()
initRecipeSteps()
}

private fun initRecipeDescription() {
viewModelScope.launch {
makingRecipeRepository.fetchRecipeDescription()
makingRecipeRepository
.fetchRecipeDescription()
.onSuccess { existingRecipe ->
existingRecipe?.let {
recipeId = it.recipeDescriptionId
Expand All @@ -94,11 +94,13 @@ class RecipeMakingViewModel2
}
}

private fun initRecipeSteps() {
fun initRecipeSteps() {
viewModelScope.launch {
stepMakingRepository.fetchRecipeSteps()
stepMakingRepository
.fetchRecipeSteps()
.onSuccess { steps ->
_currentStepImages.value = steps?.map { it.toRecipeStepImage() } ?: emptyList()
println("currentStepImages: ${currentStepImages.value}")
}.onFailure {
_currentStepImages.value = emptyList()
}
Expand All @@ -114,6 +116,8 @@ class RecipeMakingViewModel2
isLoading = false,
file = File(imageUri),
sequence = sequence,
description = description,
cookingTime = cookingTime,
)

private fun updateSingleStepImage(
Expand Down Expand Up @@ -165,7 +169,7 @@ class RecipeMakingViewModel2
thumbnailFile: File,
) {
_thumbnailUri.value = uri
uploadSingleImage(thumbnailFile)
uploadSingleThumbnailImage(thumbnailFile)
}

fun changeCurrentStepImage(
Expand All @@ -184,22 +188,32 @@ class RecipeMakingViewModel2
}
}

private fun uploadSingleImage(file: File) {
private fun uploadSingleThumbnailImage(file: File) {
viewModelScope.launch(coroutineExceptionHandler) {
val presignedUrl = makingRecipeRepository.fetchImageUri(file.name)
uploadImageToS3(presignedUrl, file)
uploadThumbnailImageToS3(presignedUrl, file)
}
}

private suspend fun uploadImageToS3(
private suspend fun uploadThumbnailImageToS3(
presignedUrl: String,
file: File,
) {
runCatching {
makingRecipeRepository.uploadImageToS3(presignedUrl, file)
}.onSuccess {
thumbnailTitle = file.name
_uiEvent.value = Event(RecipeMakingEvent2.PostImageSuccessful)
}.onFailure {
_uiEvent.value = Event(RecipeMakingEvent2.PostImageFailure)
}
}

private suspend fun uploadImageToS3(
presignedUrl: String,
file: File,
) {
runCatching {
makingRecipeRepository.uploadImageToS3(presignedUrl, file)
}.onFailure {
_uiEvent.value = Event(RecipeMakingEvent2.PostImageFailure)
}
Expand All @@ -226,10 +240,14 @@ class RecipeMakingViewModel2
}

private fun uploadStepImages() {
viewModelScope.launch(coroutineExceptionHandler) {
currentStepImages.value?.forEach { stepImage ->
currentStepImages.value?.forEach { stepImage ->
viewModelScope.launch(coroutineExceptionHandler) {
if (!stepImage.uploaded) {
println("uploaded : ${stepImage.uploaded}")
uploadStepImage(stepImage)
recipeId?.let { id ->
saveRecipeSteps(id)
}
}
}
}
Expand Down Expand Up @@ -262,6 +280,9 @@ class RecipeMakingViewModel2

override fun onConfirm() {
viewModelScope.launch {
saveRecipeSteps(recipeId ?: return@launch)
saveRecipeDescription()

if (!validateDescriptionForm()) {
_uiEvent.value = Event(RecipeMakingEvent2.DescriptionFormNotCompleted)
_isMakingStepButtonClicked.value = true
Expand Down Expand Up @@ -292,7 +313,8 @@ class RecipeMakingViewModel2
return@launch
}

makingRecipeRepository.postNewRecipe(recipeCreation)
makingRecipeRepository
.postNewRecipe(recipeCreation)
.onSuccess {
_isLoading.value = false
recipeId?.let {
Expand All @@ -307,8 +329,8 @@ class RecipeMakingViewModel2
}
}

private fun validateDescriptionForm(): Boolean {
return !categoryContent.value.isNullOrBlank() &&
private fun validateDescriptionForm(): Boolean =
!categoryContent.value.isNullOrBlank() &&
!introductionContent.value.isNullOrBlank() &&
difficultySelectedValue.value != null &&
!ingredientContent.value.isNullOrBlank() &&
Expand All @@ -317,10 +339,9 @@ class RecipeMakingViewModel2
hourContent.value != null &&
minuteContent.value != null &&
secondContent.value != null
}

private suspend fun recipeCreation(): RecipeCreation? {
return makingRecipeRepository.fetchTotalRecipeData().getOrNull()?.let { recipeData ->
private suspend fun recipeCreation(): RecipeCreation? =
makingRecipeRepository.fetchTotalRecipeData().getOrNull()?.let { recipeData ->
RecipeCreation(
title = recipeData.title,
thumbnail = recipeData.thumbnail,
Expand All @@ -332,7 +353,6 @@ class RecipeMakingViewModel2
introduction = recipeData.introduction,
)
}
}

private fun restoreDescriptionContents(existingRecipe: RecipeDescription) {
with(existingRecipe) {
Expand All @@ -341,9 +361,9 @@ class RecipeMakingViewModel2
difficultySelectedValue.value = difficulty.toFloat() / 2
introductionContent.value = description
val timeParts = cookingTime.split(SEPARATOR_TIME)
hourContent.value = timeParts[0]
minuteContent.value = timeParts[1]
secondContent.value = timeParts[2]
hourContent.value = if (timeParts[0] == "00") "" else timeParts[0]
minuteContent.value = if (timeParts[1] == "00") "" else timeParts[1]
secondContent.value = if (timeParts[2] == "00") "" else timeParts[2]
thumbnailTitle = thumbnail
categoryContent.value = categories.joinToString()
_thumbnailUri.value = Uri.parse(imageUri)
Expand All @@ -365,49 +385,52 @@ class RecipeMakingViewModel2
RecipeDescription(
recipeDescriptionId = recipeId ?: return,
categories =
categoryContent.value?.split(SEPARATOR_INGREDIENTS)
categoryContent.value
?.split(SEPARATOR_INGREDIENTS)
?.filter { it.trim().isNotEmpty() || it.trim().isNotBlank() } ?: emptyList(),
cookingTime = formatTimeRequired(),
description = introductionContent.value ?: "",
difficulty = (difficultySelectedValue.value?.times(2))?.toInt() ?: 0,
ingredients =
ingredientContent.value?.split(SEPARATOR_INGREDIENTS)
ingredientContent.value
?.split(SEPARATOR_INGREDIENTS)
?.filter { it.trim().isNotEmpty() || it.trim().isNotBlank() } ?: emptyList(),
thumbnail = thumbnailTitle ?: "",
title = titleContent.value ?: "",
imageUri = thumbnailUri.value.toString(),
)

makingRecipeRepository.saveRecipeDescription(recipeDescription)
makingRecipeRepository
.saveRecipeDescription(recipeDescription)
.onSuccess { _uiEvent.value = Event(RecipeMakingEvent2.RecipeSavingSuccessful) }
.onFailure { _uiEvent.value = Event(RecipeMakingEvent2.RecipeSavingFailure) }
}

private suspend fun saveRecipeSteps(recipeId: Long) {
currentStepImages.value?.forEachIndexed { index, image ->
stepMakingRepository.saveRecipeStep(
recipeId,
RecipeStepMaking(
1L,
stepMakingRepository
.saveRecipeStep(
recipeId,
image.description,
image.imageTitle,
index + 1,
image.uri.toString(),
image.cookingTime,
imageUploaded = image.uploaded,
),
)
RecipeStepMaking(
1L,
recipeId,
image.description,
image.imageTitle,
index + 1,
image.uri.toString(),
image.cookingTime,
imageUploaded = image.uploaded,
),
)
}
}

private fun formatTimeRequired(): String {
return FORMAT_TIME_REQUIRED.format(
private fun formatTimeRequired(): String =
FORMAT_TIME_REQUIRED.format(
hourContent.value?.toIntOrNull() ?: 0,
minuteContent.value?.toIntOrNull() ?: 0,
secondContent.value?.toIntOrNull() ?: 0,
)
}

override fun onAddImage() {
_uiEvent.value = Event(RecipeMakingEvent2.AddThumbnailImage)
Expand All @@ -423,7 +446,14 @@ class RecipeMakingViewModel2

override fun onDelete(id: Int) {
_currentStepImages.value = currentStepImages.value?.filter { it.itemId != id }
_uiEvent.value = Event(RecipeMakingEvent2.ImageDeletionSuccessful(id))

viewModelScope.launch {
recipeId?.let { recipeId ->
stepMakingRepository.deleteRecipeStepsNonAsync(recipeId)
saveRecipeSteps(recipeId)
_uiEvent.value = Event(RecipeMakingEvent2.ImageDeletionSuccessful(id))
}
}
}

override fun onOrderChange(items: List<RecipeStepImage>) {
Expand All @@ -434,12 +464,13 @@ class RecipeMakingViewModel2
viewModelScope.launch(coroutineExceptionHandler) {
val recipeId = recipeId
if (recipeId != null) {
println("recipeId : $recipeId")
saveRecipeSteps(recipeId)
}
_uiEvent.value =
Event(
RecipeMakingEvent2.NavigateToMakingStep(
sequence = currentStepImages.value?.indexOf(item) ?: return@launch,
sequence = currentStepImages.value?.indexOf(item)?.plus(1) ?: return@launch,
),
)
}
Expand Down
Loading

0 comments on commit 46812d0

Please sign in to comment.