Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT/#44] 서버통신 중 로딩뷰 구현 #55

Merged
merged 7 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions data/src/main/java/kr/genti/data/dto/request/GenerateRequestDto.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kr.genti.domain.entity.request.GenerateRequestModel
import kr.genti.domain.enums.CameraAngle
import kr.genti.domain.enums.PictureRatio
import kr.genti.domain.enums.ShotCoverage

@Serializable
data class GenerateRequestDto(
@SerialName("prompt")
val prompt: String,
@SerialName("postPictureKey")
val postPictureKey: String,
@SerialName("posePictureKey")
val posePictureKey: String?,
@SerialName("facePictureKeyList")
val facePictureKeyList: List<String>,
@SerialName("cameraAngle")
val cameraAngle: CameraAngle,
@SerialName("shotCoverage")
val shotCoverage: ShotCoverage,
@SerialName("pictureRatio")
val pictureRatio: PictureRatio,
)

fun GenerateRequestModel.toDto() = GenerateRequestDto(prompt, postPictureKey, facePictureKeyList, cameraAngle, shotCoverage)
fun GenerateRequestModel.toDto() =
GenerateRequestDto(
prompt,
posePictureKey,
facePictureKeyList,
cameraAngle,
shotCoverage,
pictureRatio,
)
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package kr.genti.domain.entity.request

import kr.genti.domain.enums.CameraAngle
import kr.genti.domain.enums.PictureRatio
import kr.genti.domain.enums.ShotCoverage

data class GenerateRequestModel(
val prompt: String,
val postPictureKey: String,
val posePictureKey: String?,
val facePictureKeyList: List<String>,
val cameraAngle: CameraAngle,
val shotCoverage: ShotCoverage,
val pictureRatio: PictureRatio,
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package kr.genti.domain.enums

enum class ImageRatio(private val description: String) {
THREE("3:2"),
TWO("2:3"),
enum class PictureRatio(private val description: String) {
THREE_TWO("3:2"),
TWO_THREE("2:3"),
;

override fun toString(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(R.layout.activity_main) {
setStatusBarColor()
}

private fun initBnvItemIconTintList() {
fun initBnvItemIconTintList() {
with(binding.bnvMain) {
itemIconTintList = null
selectedItemId = R.id.menu_feed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseFragment
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.setStatusBarColor
import kr.genti.core.state.UiState
import kr.genti.presentation.R
import kr.genti.presentation.databinding.FragmentCreateBinding

Expand All @@ -31,6 +32,7 @@ class CreateFragment() : BaseFragment<FragmentCreateBinding>(R.layout.fragment_c
initView()
initBackBtnListener()
observeProgressBar()
observeGeneratingState()
}

private fun initView() {
Expand Down Expand Up @@ -72,6 +74,18 @@ class CreateFragment() : BaseFragment<FragmentCreateBinding>(R.layout.fragment_c
}.launchIn(lifecycleScope)
}

private fun observeGeneratingState() {
viewModel.totalGeneratingState.flowWithLifecycle(lifecycle).onEach { state ->
if (state == UiState.Loading) {
setStatusBarColor(R.color.background_50)
binding.layoutLoading.isVisible = true
} else {
setStatusBarColor(R.color.background_white)
binding.layoutLoading.isVisible = false
}
}.launchIn(lifecycleScope)
}

companion object {
const val PROPERTY_PROGRESS = "progress"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import kr.genti.domain.entity.response.S3PresignedUrlModel
import kr.genti.domain.entity.response.emptyImageFileModel
import kr.genti.domain.enums.CameraAngle
import kr.genti.domain.enums.FileType
import kr.genti.domain.enums.ImageRatio
import kr.genti.domain.enums.PictureRatio
import kr.genti.domain.enums.ShotCoverage
import kr.genti.domain.repository.CreateRepository
import kr.genti.domain.repository.UploadRepository
Expand All @@ -36,7 +36,7 @@ class CreateViewModel
var plusImage = emptyImageFileModel()
val isWritten = MutableLiveData(false)

val selectedRatio = MutableLiveData<ImageRatio>()
val selectedRatio = MutableLiveData<PictureRatio>()
val selectedAngle = MutableLiveData<CameraAngle>()
val selectedCoverage = MutableLiveData<ShotCoverage>()
val isSelected = MutableLiveData(false)
Expand All @@ -56,8 +56,8 @@ class CreateViewModel
private val _getRandomPromptState = MutableStateFlow<UiState<PromptModel>>(UiState.Empty)
val getRandomPromptState: StateFlow<UiState<PromptModel>> = _getRandomPromptState

private val _totalGeneratingResult = MutableSharedFlow<Boolean>()
val totalGeneratingResult: SharedFlow<Boolean> = _totalGeneratingResult
private val _totalGeneratingState = MutableStateFlow<UiState<Boolean>>(UiState.Empty)
val totalGeneratingState: StateFlow<UiState<Boolean>> = _totalGeneratingState

private var uploadCheckList = mutableListOf(false, false, false, true)
private var plusImageS3Key: String? = null
Expand All @@ -75,7 +75,7 @@ class CreateViewModel
isWritten.value = prompt.value?.isNotEmpty()
}

fun selectRatio(item: ImageRatio) {
fun selectRatio(item: PictureRatio) {
selectedRatio.value = item
checkSelected()
}
Expand Down Expand Up @@ -123,6 +123,12 @@ class CreateViewModel
}

fun getS3PresignedUrls() {
_totalGeneratingState.value = UiState.Loading
getSingleS3Url()
getMultiUrls()
}

private fun getSingleS3Url() {
if (plusImage.id != (-1).toLong()) {
uploadCheckList[3] = false
viewModelScope.launch {
Expand All @@ -136,10 +142,13 @@ class CreateViewModel
plusImageS3Key = uriModel.s3Key
postSingleImage(uriModel)
}.onFailure {
_totalGeneratingResult.emit(false)
_totalGeneratingState.value = UiState.Failure(it.message.toString())
}
}
}
}

private fun getMultiUrls() {
viewModelScope.launch {
createRepository.getS3MultiUrl(
listOf(
Expand All @@ -151,7 +160,7 @@ class CreateViewModel
imageS3KeyList = uriList.map { it.s3Key }
postMultiImage(uriList)
}.onFailure {
_totalGeneratingResult.emit(false)
_totalGeneratingState.value = UiState.Failure(it.message.toString())
}
}
}
Expand All @@ -164,7 +173,7 @@ class CreateViewModel
uploadCheckList[3] = true
checkAllUploadFinished()
}.onFailure {
_totalGeneratingResult.emit(false)
_totalGeneratingState.value = UiState.Failure(it.message.toString())
}
}
}
Expand All @@ -177,30 +186,31 @@ class CreateViewModel
uploadCheckList[i] = true
if (i == 2) checkAllUploadFinished()
}.onFailure {
_totalGeneratingResult.emit(false)
_totalGeneratingState.value = UiState.Failure(it.message.toString())
return@launch
}
}
}
}

// TODO: request 수정
// TODO: plusImageS3Key nullable로 수정
private fun checkAllUploadFinished() {
if (uploadCheckList.all { it }) {
viewModelScope.launch {
createRepository.postToGenerate(
GenerateRequestModel(
prompt.value ?: return@launch,
plusImageS3Key ?: return@launch,
plusImageS3Key ?: "",
imageS3KeyList ?: return@launch,
selectedAngle.value ?: return@launch,
selectedCoverage.value ?: return@launch,
selectedRatio.value ?: return@launch,
),
)
.onSuccess {
_totalGeneratingResult.emit(true)
_totalGeneratingState.value = UiState.Success(it)
}.onFailure {
_totalGeneratingResult.emit(false)
_totalGeneratingState.value = UiState.Failure(it.message.toString())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package kr.genti.presentation.main.create

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.SpannableString
Expand All @@ -25,16 +26,20 @@ import kr.genti.core.extension.getFileName
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.stringOf
import kr.genti.core.extension.toast
import kr.genti.core.state.UiState
import kr.genti.domain.entity.response.ImageFileModel
import kr.genti.presentation.R
import kr.genti.presentation.databinding.FragmentSelfieBinding
import kr.genti.presentation.main.MainActivity
import kr.genti.presentation.main.feed.FeedFragment
import kr.genti.presentation.result.waiting.WaitingActivity
import kotlin.math.max

@AndroidEntryPoint
class SelfieFragment() : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_selfie) {
private val viewModel by activityViewModels<CreateViewModel>()
lateinit var activityResult: ActivityResultLauncher<PickVisualMediaRequest>
private lateinit var photoPickerResult: ActivityResultLauncher<PickVisualMediaRequest>
private lateinit var waitingResult: ActivityResultLauncher<Intent>

override fun onViewCreated(
view: View,
Expand All @@ -49,7 +54,8 @@ class SelfieFragment() : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_s
setGalleryImage()
setBulletPointList()
setGuideListBlur()
observeGetS3UrlResult()
initWaitingResult()
observeGeneratingState()
}

override fun onResume() {
Expand Down Expand Up @@ -78,10 +84,10 @@ class SelfieFragment() : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_s
private fun initAddImageBtnListener() {
with(binding) {
btnSelfieAdd.setOnSingleClickListener {
activityResult.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
photoPickerResult.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
layoutAddedImage.setOnSingleClickListener {
activityResult.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
photoPickerResult.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
}
}
}
Expand All @@ -93,7 +99,7 @@ class SelfieFragment() : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_s
}

private fun setGalleryImage() {
activityResult =
photoPickerResult =
registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(3)) { uris ->
if (uris.isNotEmpty()) {
with(viewModel) {
Expand Down Expand Up @@ -121,7 +127,8 @@ class SelfieFragment() : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_s
val imageViews =
with(binding) { listOf(ivAddedImage1, ivAddedImage2, ivAddedImage3) }
imageViews.forEach { it.setImageDrawable(null) }
viewModel.imageList.take(3).forEachIndexed { index, imageFile -> imageViews[index].load(imageFile.url) }
viewModel.imageList.take(3)
.forEachIndexed { index, imageFile -> imageViews[index].load(imageFile.url) }
binding.layoutAddedImage.isVisible = true
}
}
Expand Down Expand Up @@ -161,14 +168,34 @@ class SelfieFragment() : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_s
}
}

private fun observeGetS3UrlResult() {
viewModel.totalGeneratingResult.flowWithLifecycle(lifecycle).onEach { result ->
if (!result) {
toast(stringOf(R.string.error_msg))
} else {
Intent(requireActivity(), WaitingActivity::class.java).apply {
startActivity(this)
private fun initWaitingResult() {
if (!::waitingResult.isInitialized) {
waitingResult =
registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.fcv_main, FeedFragment())
.commit()
(requireActivity() as? MainActivity)?.initBnvItemIconTintList()
}
}
}
}

private fun observeGeneratingState() {
viewModel.totalGeneratingState.flowWithLifecycle(lifecycle).onEach { state ->
when (state) {
is UiState.Success -> {
waitingResult.launch(Intent(requireContext(), WaitingActivity::class.java))
}

is UiState.Failure -> {
toast(stringOf(R.string.error_msg))
}

else -> return@onEach
}
}.launchIn(lifecycleScope)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package kr.genti.presentation.main.feed

import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
Expand Down Expand Up @@ -79,6 +80,13 @@ class FeedFragment() : BaseFragment<FragmentFeedBinding>(R.layout.fragment_feed)

private fun observeGetExampleItemsState() {
viewModel.getExampleItemsState.flowWithLifecycle(lifecycle).onEach { state ->
if (state == UiState.Loading) {
setStatusBarColor(R.color.background_50)
binding.layoutLoading.isVisible = true
} else {
setStatusBarColor(R.color.background_white)
binding.layoutLoading.isVisible = false
}
when (state) {
is UiState.Success -> adapter.addItemList(state.data)
is UiState.Failure -> toast(stringOf(R.string.error_msg))
Expand Down
Loading
Loading