Skip to content

Commit

Permalink
[MERGE] #155 -> develop
Browse files Browse the repository at this point in the history
[REFACTOR/#155] 사진 생성 요청뷰 UI 리디자인
  • Loading branch information
Marchbreeze authored Oct 29, 2024
2 parents 2a75170 + 1156001 commit 42c3c45
Show file tree
Hide file tree
Showing 34 changed files with 442 additions and 2,428 deletions.
10 changes: 10 additions & 0 deletions core/src/main/java/kr/genti/core/extension/ViewExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import android.graphics.LinearGradient
import android.graphics.RenderEffect
import android.graphics.Shader
import android.os.Build
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ImageSpan
import android.view.View
import android.widget.TextView

Expand Down Expand Up @@ -44,3 +47,10 @@ fun TextView.setGradientText(startColor: Int, endColor: Int) {
Shader.TileMode.CLAMP
)
}

fun TextView.setTextWithImage(text: String, imageResId: Int) {
val spannableString = SpannableString(" $text")
val imageSpan = ImageSpan(context, imageResId, ImageSpan.ALIGN_BOTTOM)
spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
this.text = spannableString
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,16 @@ import kr.genti.domain.enums.ShotCoverage
data class CreateRequestDto(
@SerialName("prompt")
val prompt: String,
@SerialName("posePicture")
val posePicture: KeyRequestDto?,
@SerialName("facePictureList")
val facePictureList: List<KeyRequestDto>,
@SerialName("cameraAngle")
val cameraAngle: CameraAngle,
@SerialName("shotCoverage")
val shotCoverage: ShotCoverage,
@SerialName("pictureRatio")
val pictureRatio: PictureRatio,
) {
companion object {
fun CreateRequestModel.toDto() =
CreateRequestDto(
prompt,
posePicture?.toDto(),
facePictureList.map { it.toDto() },
cameraAngle,
shotCoverage,
pictureRatio,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import kr.genti.domain.enums.ShotCoverage

data class CreateRequestModel(
val prompt: String,
val posePicture: KeyRequestModel?,
val facePictureList: List<KeyRequestModel>,
val cameraAngle: CameraAngle,
val shotCoverage: ShotCoverage,
val pictureRatio: PictureRatio,
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,12 @@ import kr.genti.domain.entity.request.CreateRequestModel
import kr.genti.domain.entity.request.KeyRequestModel
import kr.genti.domain.entity.request.S3RequestModel
import kr.genti.domain.entity.response.ImageFileModel
import kr.genti.domain.entity.response.ImageFileModel.Companion.emptyImageFileModel
import kr.genti.domain.entity.response.S3PresignedUrlModel
import kr.genti.domain.enums.CameraAngle
import kr.genti.domain.enums.FileType
import kr.genti.domain.enums.PictureRatio
import kr.genti.domain.enums.ShotCoverage
import kr.genti.domain.repository.CreateRepository
import kr.genti.domain.repository.UploadRepository
import javax.inject.Inject
import kotlin.random.Random

@HiltViewModel
class CreateViewModel
Expand All @@ -33,12 +29,9 @@ constructor(
private val uploadRepository: UploadRepository,
) : ViewModel() {
val prompt = MutableLiveData<String>()
var plusImage = emptyImageFileModel()
val isWritten = MutableLiveData(false)

val selectedRatio = MutableLiveData<PictureRatio>()
val selectedAngle = MutableLiveData<CameraAngle>()
val selectedCoverage = MutableLiveData<ShotCoverage>()
val isSelected = MutableLiveData(false)

var imageList = listOf<ImageFileModel>()
Expand All @@ -47,12 +40,9 @@ constructor(
private val _currentPercent = MutableStateFlow<Int>(33)
val currentPercent: StateFlow<Int> = _currentPercent

private var currentPrompt: String = ""

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

private var plusImageS3Key = KeyRequestModel(null)
private var imageS3KeyList = listOf<KeyRequestModel>()

fun modCurrentPercent(amount: Int) {
Expand All @@ -65,32 +55,14 @@ constructor(

fun selectRatio(item: PictureRatio) {
selectedRatio.value = item
checkSelected()
}

fun selectAngle(item: CameraAngle) {
selectedAngle.value = item
checkSelected()
}

fun selectFrame(item: ShotCoverage) {
selectedCoverage.value = item
checkSelected()
}

private fun checkSelected() {
isSelected.value =
selectedRatio.value != null && selectedAngle.value != null && selectedCoverage.value != null
isSelected.value = selectedRatio.value != null
}

fun startSendingImages() {
_totalGeneratingState.value = UiState.Loading
viewModelScope.launch {
runCatching {
listOfNotNull(
if (plusImage.id != (-1).toLong()) async { getSingleS3Url() } else null,
async { getMultiS3Urls() },
).awaitAll()
getMultiS3Urls()
}.onSuccess {
postToGenerateImage()
}.onFailure {
Expand All @@ -99,18 +71,6 @@ constructor(
}
}

private suspend fun getSingleS3Url() {
createRepository.getS3SingleUrl(
S3RequestModel(FileType.USER_UPLOADED_IMAGE, plusImage.name),
)
.onSuccess { uriModel ->
plusImageS3Key = KeyRequestModel(uriModel.s3Key)
postSingleImage(uriModel)
}.onFailure {
_totalGeneratingState.value = UiState.Failure(it.message.toString())
}
}

private suspend fun getMultiS3Urls() {
createRepository.getS3MultiUrl(
listOf(
Expand All @@ -126,13 +86,6 @@ constructor(
}
}

private suspend fun postSingleImage(urlModel: S3PresignedUrlModel) {
uploadRepository.uploadImage(urlModel.url, plusImage.url)
.onFailure {
_totalGeneratingState.value = UiState.Failure(it.message.toString())
}
}

private suspend fun postMultiImage(urlModelList: List<S3PresignedUrlModel>) {
urlModelList.mapIndexed { i, urlModel ->
viewModelScope.async {
Expand All @@ -149,10 +102,7 @@ constructor(
createRepository.postToCreate(
CreateRequestModel(
prompt.value ?: return@launch,
plusImageS3Key,
imageS3KeyList,
selectedAngle.value ?: return@launch,
selectedCoverage.value ?: return@launch,
selectedRatio.value ?: return@launch,
),
)
Expand All @@ -168,12 +118,6 @@ constructor(
_totalGeneratingState.value = UiState.Empty
}

fun getRandomPrompt(): String {
val randomPrompt = promptList[Random.nextInt(promptList.size)]
if (randomPrompt != currentPrompt) currentPrompt = randomPrompt
return currentPrompt
}

companion object {
val promptList =
listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import androidx.viewpager2.widget.ViewPager2
import dagger.hilt.android.AndroidEntryPoint
import kr.genti.core.base.BaseFragment
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.setTextWithImage
import kr.genti.core.extension.stringOf
import kr.genti.presentation.R
import kr.genti.presentation.create.CreateViewModel.Companion.promptList
import kr.genti.presentation.databinding.FragmentDefineBinding
Expand Down Expand Up @@ -37,7 +39,17 @@ class DefineFragment() : BaseFragment<FragmentDefineBinding>(R.layout.fragment_d
}

private fun initView() {
binding.vm = viewModel
with(binding) {
vm = viewModel
tvCreateScriptSubtitle1.setTextWithImage(
stringOf(R.string.create_tv_script_subtitle_1),
R.drawable.ic_check,
)
tvCreateScriptSubtitle2.setTextWithImage(
stringOf(R.string.create_tv_script_subtitle_2),
R.drawable.ic_check,
)
}
}

private fun initCreateBtnListener() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ import android.app.Activity.RESULT_OK
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.SpannableString
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.style.BulletSpan
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.ActivityResultLauncher
Expand All @@ -27,6 +23,7 @@ import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseFragment
import kr.genti.core.extension.getFileName
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.setTextWithImage
import kr.genti.core.extension.stringOf
import kr.genti.core.extension.toast
import kr.genti.core.state.UiState
Expand All @@ -39,7 +36,6 @@ import kr.genti.presentation.util.AmplitudeManager
import kr.genti.presentation.util.AmplitudeManager.EVENT_CLICK_BTN
import kr.genti.presentation.util.AmplitudeManager.PROPERTY_BTN
import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
import kotlin.math.max

@AndroidEntryPoint
class SelfieFragment : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_selfie) {
Expand All @@ -61,8 +57,6 @@ class SelfieFragment : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_sel
initRequestCreateBtnListener()
setGalleryImageWithPhotoPicker()
setGalleryImageWithGalleryPicker()
setBulletPointList()
setGuideListBlur()
initWaitingResult()
observeGeneratingState()
}
Expand All @@ -74,7 +68,21 @@ class SelfieFragment : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_sel
}

private fun initView() {
binding.vm = viewModel
with(binding) {
vm = viewModel
tvSelfieGuide1.setTextWithImage(
stringOf(R.string.selfie_tv_guide_1),
R.drawable.ic_check,
)
tvSelfieGuide2.setTextWithImage(
stringOf(R.string.selfie_tv_guide_2),
R.drawable.ic_check,
)
tvSelfieGuide3.setTextWithImage(
stringOf(R.string.selfie_tv_guide_3),
R.drawable.ic_check,
)
}
}

private fun initBackPressedListener() {
Expand All @@ -89,28 +97,18 @@ class SelfieFragment : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_sel
}

private fun initAddImageBtnListener() {
with(binding) {
btnSelfieAdd.setOnSingleClickListener {
AmplitudeManager.trackEvent(
EVENT_CLICK_BTN,
mapOf(PROPERTY_PAGE to "create3"),
mapOf(PROPERTY_BTN to "selectpic"),
)
checkAndGetImages()
}
layoutAddedImage.setOnSingleClickListener {
AmplitudeManager.trackEvent(
EVENT_CLICK_BTN,
mapOf(PROPERTY_PAGE to "create3"),
mapOf(PROPERTY_BTN to "reselectpic"),
)
checkAndGetImages()
}
binding.btnSelfieAdd.setOnSingleClickListener {
AmplitudeManager.trackEvent(
EVENT_CLICK_BTN,
mapOf(PROPERTY_PAGE to "create3"),
mapOf(PROPERTY_BTN to "selectpic"),
)
checkAndGetImages()
}
}

private fun initRequestCreateBtnListener() {
binding.btnSelfieNext.setOnSingleClickListener {
binding.btnCreate.setOnSingleClickListener {
AmplitudeManager.trackEvent(
EVENT_CLICK_BTN,
mapOf(PROPERTY_PAGE to "create3"),
Expand Down Expand Up @@ -177,62 +175,22 @@ class SelfieFragment : BaseFragment<FragmentSelfieBinding>(R.layout.fragment_sel
}
isCompleted.value = uris.size == 3
}
with(binding) {
listOf(ivAddedImage1, ivAddedImage2, ivAddedImage3).apply {
forEach { it.setImageDrawable(null) }
uris.take(size).forEachIndexed { index, uri ->
this[index].load(uri)
}
}
}
binding.layoutAddedImage.isVisible = uris.isNotEmpty()
setSavedImages()
}

private fun setSavedImages() {
if (viewModel.imageList.isNotEmpty()) {
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) }
binding.layoutAddedImage.isVisible = true
}
}

private fun setBulletPointList() {
val points =
listOf(
stringOf(R.string.selfie_tv_guide_one),
stringOf(R.string.selfie_tv_guide_two),
stringOf(R.string.selfie_tv_guide_three),
stringOf(R.string.selfie_tv_guide_four),
)
val spannableStringBuilder = SpannableStringBuilder()
points.forEach { point ->
val spannableString =
SpannableString(point).apply {
setSpan(
BulletSpan(15),
0,
point.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
)
}
with(spannableStringBuilder) {
append(spannableString)
append("\n")
}
}
binding.tvSelfieGuideBody.text = spannableStringBuilder
}

private fun setGuideListBlur() {
with(binding) {
svSelfieGuide.setOnScrollChangeListener { _, _, scrollY, _, _ ->
ivSelfieBlurBottom.alpha = max(0.0, (1 - scrollY / 500f).toDouble()).toFloat()
ivSelfieBlurTop.alpha = 1 - max(0.0, (1 - scrollY / 100f).toDouble()).toFloat()
listOf(ivAddedImage1, ivAddedImage2, ivAddedImage3).apply {
forEach { it.setImageDrawable(null) }
viewModel.imageList.take(size).forEachIndexed { index, file ->
this[index].load(file.url)
}
}
layoutAddedImage.isVisible = viewModel.imageList.isNotEmpty()
layoutExampleImage.isVisible = viewModel.imageList.isEmpty()
btnSelfieAdd.text =
if (viewModel.imageList.isEmpty()) stringOf(R.string.selfie_tv_btn_select)
else stringOf(R.string.selfie_tv_btn_reselect)
}
}

Expand Down
Loading

0 comments on commit 42c3c45

Please sign in to comment.