From fda61728b81522f313f4e2ae8863116d9d033285 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 00:24:24 +0900 Subject: [PATCH 01/15] =?UTF-8?q?feat=20:=20upload=20api=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/core/data/api/MusicApi.kt | 8 ++++++++ .../catchytape/core/data/api/UploadApi.kt | 20 +++++++++++++++++++ .../catchytape/core/data/di/ApiModule.kt | 7 +++++++ .../core/data/model/MusicRequest.kt | 7 +++++++ .../catchytape/core/data/model/UrlResponse.kt | 5 +++++ 5 files changed, 47 insertions(+) create mode 100644 android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UploadApi.kt create mode 100644 android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicRequest.kt create mode 100644 android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/UrlResponse.kt diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt index 83c712b..f93f719 100644 --- a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/MusicApi.kt @@ -1,12 +1,20 @@ package com.ohdodok.catchytape.core.data.api import com.ohdodok.catchytape.core.data.model.MusicGenresResponse +import com.ohdodok.catchytape.core.data.model.MusicRequest import retrofit2.Response +import retrofit2.http.Body import retrofit2.http.GET +import retrofit2.http.POST interface MusicApi { @GET("musics/genres") suspend fun getGenres(): Response + @POST("musics") + suspend fun postMusic( + @Body music: MusicRequest + ): Response + } \ No newline at end of file diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UploadApi.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UploadApi.kt new file mode 100644 index 0000000..902ee7f --- /dev/null +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/api/UploadApi.kt @@ -0,0 +1,20 @@ +package com.ohdodok.catchytape.core.data.api + +import com.ohdodok.catchytape.core.data.model.UrlResponse +import retrofit2.Response +import retrofit2.http.Headers +import retrofit2.http.POST + +interface UploadApi { + + @POST("upload/music") + @Headers("Content-Type: audio/mpeg") + suspend fun uploadMusic( + ): Response + + @POST("upload/image") + @Headers("Content-Type: image/png") + suspend fun uploadImage( + ): Response + +} \ No newline at end of file diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/di/ApiModule.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/di/ApiModule.kt index 9d2c873..7ad8229 100644 --- a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/di/ApiModule.kt +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/di/ApiModule.kt @@ -1,6 +1,7 @@ package com.ohdodok.catchytape.core.data.di import com.ohdodok.catchytape.core.data.api.MusicApi +import com.ohdodok.catchytape.core.data.api.UploadApi import com.ohdodok.catchytape.core.data.api.UserApi import dagger.Module import dagger.Provides @@ -24,4 +25,10 @@ object ApiModule { fun provideMusicApi(retrofit: Retrofit): MusicApi { return retrofit.create(MusicApi::class.java) } + + @Provides + @Singleton + fun provideUploadApi(retrofit: Retrofit): UploadApi { + return retrofit.create(UploadApi::class.java) + } } \ No newline at end of file diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicRequest.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicRequest.kt new file mode 100644 index 0000000..ed724fe --- /dev/null +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/MusicRequest.kt @@ -0,0 +1,7 @@ +package com.ohdodok.catchytape.core.data.model + +data class MusicRequest ( + val title: String, + val cover: String, + val file: String +) \ No newline at end of file diff --git a/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/UrlResponse.kt b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/UrlResponse.kt new file mode 100644 index 0000000..c359d14 --- /dev/null +++ b/android/core/data/src/main/java/com/ohdodok/catchytape/core/data/model/UrlResponse.kt @@ -0,0 +1,5 @@ +package com.ohdodok.catchytape.core.data.model + +data class UrlResponse( + val url: String +) \ No newline at end of file From 2436eb8475b7cd3b7397ed3f0b31d27d4c274cf9 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 13:25:12 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat=20:=20=ED=8C=8C=EC=9D=BC=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EB=B2=84=ED=8A=BC=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/upload/UploadFragment.kt | 15 +++++++++------ .../feature/upload/UploadViewModel.kt | 6 ++++-- .../src/main/res/layout/fragment_upload.xml | 19 ++++++++++++++++--- .../upload/src/main/res/values/strings.xml | 4 ++++ 4 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 android/feature/upload/src/main/res/values/strings.xml diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt index 2af7630..b2e31bf 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt @@ -5,7 +5,6 @@ import android.view.View import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia -import androidx.core.net.toFile import androidx.fragment.app.viewModels import com.ohdodok.catchytape.catchytape.upload.R import com.ohdodok.catchytape.catchytape.upload.databinding.FragmentUploadBinding @@ -18,25 +17,29 @@ class UploadFragment : BaseFragment(R.layout.fragment_upl private val imagePickerLauncher = registerForActivityResult(PickVisualMedia()) { uri -> if (uri == null) return@registerForActivityResult - - viewModel.uploadImage(uri.toFile()) + viewModel.uploadImage(uri) } private val filePickerLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> if (uri == null) return@registerForActivityResult - - viewModel.uploadAudio(uri.toFile()) + viewModel.uploadAudio(uri) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.viewModel = viewModel - + setUpFileBtn() setupBackStack(binding.tbUpload) setupSelectThumbnailImage() } + private fun setUpFileBtn() { + binding.btnFile.setOnClickListener { + filePickerLauncher.launch("audio/*") + } + } + private fun setupSelectThumbnailImage() { binding.cvUploadThumbnail.setOnClickListener { imagePickerLauncher.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly)) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 2e600c7..2a031c4 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -1,5 +1,6 @@ package com.ohdodok.catchytape.feature.upload +import android.net.Uri import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import java.io.File @@ -48,12 +49,13 @@ class UploadViewModel @Inject constructor( }.launchIn(viewModelScope) } - fun uploadImage(imageFile: File) { + fun uploadImage(imageUri: Uri) { // todo : image 파일을 업로드 한다. // todo : 반환 값을 uploadedImage에 저장한다. } - fun uploadAudio(audioFile: File) { + fun uploadAudio(audioUri: Uri) { // todo : audio 파일을 업로드 한다. + val file = audioUri.path?.let { File(it) } } } \ No newline at end of file diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index 762b7ed..dd19b5d 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -68,18 +68,31 @@ + + + app:layout_constraintTop_toBottomOf="@id/btn_file"> + + 파일 업로드 + \ No newline at end of file From 85d82e13d932df4f8742ca83920c9360a23d0f73 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 13:44:33 +0900 Subject: [PATCH 03/15] =?UTF-8?q?refactor=20:=20=EC=9E=A5=EB=A5=B4=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EB=A1=9C=EC=A7=81=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/feature/upload/BindingAdapter.kt | 6 ------ .../catchytape/feature/upload/UploadViewModel.kt | 15 +++++---------- .../src/main/res/layout/fragment_upload.xml | 2 +- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt index 4af0ce0..8489ec3 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt @@ -5,12 +5,6 @@ import android.widget.ArrayAdapter import android.widget.AutoCompleteTextView import androidx.databinding.BindingAdapter - -@BindingAdapter("changeSelectedPosition") -fun AutoCompleteTextView.bindPosition(onChange: (Int) -> Unit) { - setOnItemClickListener { _, _, position, _ -> onChange(position) } -} - @BindingAdapter("list") fun AutoCompleteTextView.setAdapter(list: List) { val adapter = ArrayAdapter(this.context, R.layout.simple_list_item_1, list) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 2a031c4..76e7a3c 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -21,21 +21,16 @@ class UploadViewModel @Inject constructor( private val getMusicGenresUseCase: GetMusicGenresUseCase ) : ViewModel() { - private var uploadedImage: String? = null - + private var uploadedImage: Uri? = null + private var uploadedAudio: Uri? = null val uploadedMusicTitle = MutableStateFlow("") - - private val _uploadedMusicGenrePosition = MutableStateFlow(-1) - val uploadedMusicGenrePosition = _uploadedMusicGenrePosition.asStateFlow() + val uploadedMusicGenre= MutableStateFlow("") val isUploadEnable: StateFlow = - combine(uploadedMusicTitle, uploadedMusicGenrePosition) { title, genrePosition -> - title.isNotBlank() && genrePosition != -1 + combine(uploadedMusicTitle, uploadedMusicGenre) { title, genrePosition -> + title.isNotBlank() && genrePosition.isNotBlank() }.stateIn(viewModelScope, SharingStarted.Eagerly, false) - val onChangePosition: (Int) -> Unit = - { position: Int -> _uploadedMusicGenrePosition.value = position } - private val _musicGenres: MutableStateFlow> = MutableStateFlow(emptyList()) val musicGenres = _musicGenres.asStateFlow() diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index dd19b5d..e0169a2 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -119,7 +119,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="none" - app:changeSelectedPosition="@{viewModel.onChangePosition}" + android:text="@={viewModel.uploadedMusicGenre}" app:list="@{viewModel.musicGenres}" /> From e1b51f39cb8f65e9da333d0b65eb14835b567c3e Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 14:16:03 +0900 Subject: [PATCH 04/15] =?UTF-8?q?feat=20:=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catchytape/feature/upload/UploadFragment.kt | 13 +++++++++++++ .../catchytape/feature/upload/UploadViewModel.kt | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt index b2e31bf..3253885 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt @@ -1,6 +1,8 @@ package com.ohdodok.catchytape.feature.upload +import android.net.Uri import android.os.Bundle +import android.provider.OpenableColumns import android.view.View import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts @@ -23,6 +25,7 @@ class UploadFragment : BaseFragment(R.layout.fragment_upl private val filePickerLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> if (uri == null) return@registerForActivityResult + binding.btnFile.text = getFileName(uri) viewModel.uploadAudio(uri) } @@ -45,4 +48,14 @@ class UploadFragment : BaseFragment(R.layout.fragment_upl imagePickerLauncher.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly)) } } + + private fun getFileName(uri: Uri): String? { + val contentResolver = requireContext().contentResolver + contentResolver.query(uri, null, null, null, null)?.use { cursor -> + val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + cursor.moveToFirst() + return cursor.getString(nameIndex) + } + return null + } } \ No newline at end of file diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 76e7a3c..e8360c6 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -21,8 +21,8 @@ class UploadViewModel @Inject constructor( private val getMusicGenresUseCase: GetMusicGenresUseCase ) : ViewModel() { - private var uploadedImage: Uri? = null - private var uploadedAudio: Uri? = null +// private var uploadedImage: Uri? = null +// private var uploadedAudio: Uri? = null val uploadedMusicTitle = MutableStateFlow("") val uploadedMusicGenre= MutableStateFlow("") @@ -53,4 +53,5 @@ class UploadViewModel @Inject constructor( // todo : audio 파일을 업로드 한다. val file = audioUri.path?.let { File(it) } } + } \ No newline at end of file From c600fe4cb500f5aac7c032bb3e4a3d31c0591059 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 14:29:59 +0900 Subject: [PATCH 05/15] =?UTF-8?q?chore=20:=20glide=20library=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/core/ui/build.gradle.kts | 2 ++ .../ohdodok/catchytape/core/ui/BindingAdapters.kt | 12 ++++++++++++ android/gradle/libs.versions.toml | 2 ++ 3 files changed, 16 insertions(+) create mode 100644 android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt diff --git a/android/core/ui/build.gradle.kts b/android/core/ui/build.gradle.kts index c8d81ba..f08a30f 100644 --- a/android/core/ui/build.gradle.kts +++ b/android/core/ui/build.gradle.kts @@ -37,4 +37,6 @@ dependencies { api(libs.navigation.fragment.ktx) api(libs.navigation.ui.ktx) + + implementation(libs.glide) } \ No newline at end of file diff --git a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt new file mode 100644 index 0000000..fe02a20 --- /dev/null +++ b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt @@ -0,0 +1,12 @@ +package com.ohdodok.catchytape.core.ui + +import android.widget.ImageView +import androidx.databinding.BindingAdapter +import com.bumptech.glide.Glide + +@BindingAdapter("imageUrl") +fun ImageView.bindImg(url: String) { + Glide.with(this.context) + .load(url) + .into(this) +} \ No newline at end of file diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 32cc54c..96a1935 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -22,6 +22,7 @@ kotlinx-serialization = "1.6.0" kotlinx-serialization-converter = "1.0.0" coroutines = "1.3.5" +glide = "4.15.0" timber = "5.0.1" [libraries] @@ -53,6 +54,7 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "kotlinx-serialization-converter" } coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "coroutines" } +glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" } timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } [plugins] From 48abf4349fac054bfebc26cf6cf6975ba8330af6 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 14:38:35 +0900 Subject: [PATCH 06/15] =?UTF-8?q?feat=20:=20progress=20indicator=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/src/main/res/drawable/ic_camera.xml | 2 +- .../src/main/res/layout/fragment_upload.xml | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/android/core/ui/src/main/res/drawable/ic_camera.xml b/android/core/ui/src/main/res/drawable/ic_camera.xml index 364476e..5a798d6 100644 --- a/android/core/ui/src/main/res/drawable/ic_camera.xml +++ b/android/core/ui/src/main/res/drawable/ic_camera.xml @@ -5,5 +5,5 @@ android:viewportHeight="24"> + android:fillColor="@color/black"/> diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index e0169a2..9b54ffc 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -34,9 +34,16 @@ android:enabled="@{viewModel.isUploadEnable}" android:text="@string/complete" /> - + + + app:layout_constraintTop_toBottomOf="@id/progress_upload"> @@ -124,6 +131,5 @@ - \ No newline at end of file From 616f5a2f48e8128f8235d0b2aa1b60ee58c9c1bf Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 14:59:13 +0900 Subject: [PATCH 07/15] =?UTF-8?q?feat=20:=20=EC=99=84=EB=A3=8C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=99=9C=EC=84=B1=ED=99=94=20=EC=9C=A0=EB=AC=B4=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/upload/UploadViewModel.kt | 19 +++++++++++++------ .../src/main/res/layout/fragment_upload.xml | 5 +++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index e8360c6..aa055dd 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -21,14 +21,21 @@ class UploadViewModel @Inject constructor( private val getMusicGenresUseCase: GetMusicGenresUseCase ) : ViewModel() { -// private var uploadedImage: Uri? = null -// private var uploadedAudio: Uri? = null - val uploadedMusicTitle = MutableStateFlow("") - val uploadedMusicGenre= MutableStateFlow("") + val musicTitle = MutableStateFlow("") + val musicGenre = MutableStateFlow("") + + private val _thumbnailUrl: MutableStateFlow = MutableStateFlow("") + val thumbnailUrl = _thumbnailUrl.asStateFlow() + + private val _audioUrl: MutableStateFlow = MutableStateFlow("") + val audioUrl = _audioUrl.asStateFlow() val isUploadEnable: StateFlow = - combine(uploadedMusicTitle, uploadedMusicGenre) { title, genrePosition -> - title.isNotBlank() && genrePosition.isNotBlank() + combine(musicTitle, musicGenre, thumbnailUrl, audioUrl) { title, genre, thumbnail, audio -> + title.isNotBlank() + && genre.isNotBlank() + && thumbnail.isNotBlank() + && audio.isNotBlank() }.stateIn(viewModelScope, SharingStarted.Eagerly, false) private val _musicGenres: MutableStateFlow> = MutableStateFlow(emptyList()) diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index 9b54ffc..59aadd7 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -63,6 +63,7 @@ android:layout_height="match_parent" android:layout_gravity="center" android:background="@color/white" + imageUrl="@{viewModel.thumbnailUrl}" android:importantForAccessibility="no" /> + android:text="@={viewModel.musicTitle}" /> @@ -126,7 +127,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="none" - android:text="@={viewModel.uploadedMusicGenre}" + android:text="@={viewModel.musicGenre}" app:list="@{viewModel.musicGenres}" /> From 634e41e494384cc5539262da0d42843175cb7ff2 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 16:23:50 +0900 Subject: [PATCH 08/15] =?UTF-8?q?feat=20:=20progress=20bar=20visibility=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/usecase/GetFileUrlUseCase.kt | 18 +++++++++++ .../feature/upload/UploadViewModel.kt | 32 +++++++++++++++++-- .../src/main/res/layout/fragment_upload.xml | 10 ++++-- 3 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt new file mode 100644 index 0000000..95d55f6 --- /dev/null +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt @@ -0,0 +1,18 @@ +package com.ohdodok.catchytape.core.domain.usecase + +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import java.io.File +import javax.inject.Inject + +class GetFileUrlUseCase @Inject constructor( + +) { + operator fun invoke(file: File): Flow = flow { + // todo : file을 업로드 하고 url을 받아온다. + // todo : 임시 방편 + delay(5000) + emit("https://kr.object.ncloudstorage.com/catchy-tape-bucket2/music/2/%EC%9D%B4%EB%85%B8%EB%9E%98.mp3") + } +} \ No newline at end of file diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index aa055dd..232ef88 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -6,19 +6,23 @@ import dagger.hilt.android.lifecycle.HiltViewModel import java.io.File import javax.inject.Inject import androidx.lifecycle.viewModelScope +import com.ohdodok.catchytape.core.domain.usecase.GetFileUrlUseCase import com.ohdodok.catchytape.core.domain.usecase.GetMusicGenresUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn @HiltViewModel class UploadViewModel @Inject constructor( - private val getMusicGenresUseCase: GetMusicGenresUseCase + private val getMusicGenresUseCase: GetMusicGenresUseCase, + private val getFileUrlUseCase: GetFileUrlUseCase ) : ViewModel() { val musicTitle = MutableStateFlow("") @@ -41,6 +45,9 @@ class UploadViewModel @Inject constructor( private val _musicGenres: MutableStateFlow> = MutableStateFlow(emptyList()) val musicGenres = _musicGenres.asStateFlow() + private val _uploadUiState: MutableStateFlow = MutableStateFlow(UploadUiState()) + val uploadUiState = _uploadUiState.asStateFlow() + init { fetchGenres() } @@ -54,11 +61,30 @@ class UploadViewModel @Inject constructor( fun uploadImage(imageUri: Uri) { // todo : image 파일을 업로드 한다. // todo : 반환 값을 uploadedImage에 저장한다. + imageUri.path?.let { path -> + getFileUrlUseCase(File(path)).onEach { + _thumbnailUrl.value = it + }.launchIn(viewModelScope) + } } fun uploadAudio(audioUri: Uri) { // todo : audio 파일을 업로드 한다. - val file = audioUri.path?.let { File(it) } + audioUri.path?.let { path -> + getFileUrlUseCase(File(path)).onEach { + _uploadUiState.value = uploadUiState.value.copy(isAudioLoading = false) + _audioUrl.value = it + }.onStart { + _uploadUiState.value = uploadUiState.value.copy(isAudioLoading = true) + }.catch { + _uploadUiState.value = uploadUiState.value.copy(isAudioLoading = false) + }.launchIn(viewModelScope) + } } -} \ No newline at end of file +} + +data class UploadUiState ( + val isAudioLoading: Boolean = false, +) + diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index 59aadd7..bd1bf34 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -4,6 +4,8 @@ + + @@ -40,6 +42,8 @@ android:id="@+id/progress_upload" android:layout_width="0dp" android:layout_height="wrap_content" + android:indeterminate="true" + android:visibility="@{viewModel.uploadUiState.audioLoading ? View.VISIBLE : View.GONE}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tb_upload" /> @@ -55,7 +59,7 @@ app:cardElevation="0dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/progress_upload"> + app:layout_constraintTop_toBottomOf="@id/tb_upload"> + android:importantForAccessibility="no" + app:imageUrl="@{viewModel.thumbnailUrl}" /> Date: Wed, 22 Nov 2023 18:59:39 +0900 Subject: [PATCH 09/15] =?UTF-8?q?feat=20:=20upload=20ui=20state=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/usecase/GetFileUrlUseCase.kt | 18 ---- .../core/domain/usecase/UploadFileUseCase.kt | 24 +++++ android/core/ui/build.gradle.kts | 2 +- .../feature/upload/BindingAdapter.kt | 28 ++++++ .../feature/upload/UploadViewModel.kt | 92 ++++++++++++------- .../src/main/res/layout/fragment_upload.xml | 11 ++- 6 files changed, 117 insertions(+), 58 deletions(-) delete mode 100644 android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt create mode 100644 android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadFileUseCase.kt diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt deleted file mode 100644 index 95d55f6..0000000 --- a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/GetFileUrlUseCase.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.ohdodok.catchytape.core.domain.usecase - -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import java.io.File -import javax.inject.Inject - -class GetFileUrlUseCase @Inject constructor( - -) { - operator fun invoke(file: File): Flow = flow { - // todo : file을 업로드 하고 url을 받아온다. - // todo : 임시 방편 - delay(5000) - emit("https://kr.object.ncloudstorage.com/catchy-tape-bucket2/music/2/%EC%9D%B4%EB%85%B8%EB%9E%98.mp3") - } -} \ No newline at end of file diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadFileUseCase.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadFileUseCase.kt new file mode 100644 index 0000000..b2a7d7f --- /dev/null +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadFileUseCase.kt @@ -0,0 +1,24 @@ +package com.ohdodok.catchytape.core.domain.usecase + +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import java.io.File +import javax.inject.Inject + +class UploadFileUseCase @Inject constructor( + +) { + + fun getImgUrl(file: File): Flow = flow { + // todo : 서버 기다리는 중.. + delay(1000) + emit("https://kr.object.ncloudstorage.com/catchy-tape-bucket2/image/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202023-11-21%20180100.png") + } + + fun getAudioUrl(file: File): Flow = flow { + // todo : 서버 기다리는 중.. + delay(1000) + emit("https://kr.object.ncloudstorage.com/catchy-tape-bucket2/music/2/%EC%9D%B4%EB%85%B8%EB%9E%98.mp3") + } +} \ No newline at end of file diff --git a/android/core/ui/build.gradle.kts b/android/core/ui/build.gradle.kts index f08a30f..bfad06e 100644 --- a/android/core/ui/build.gradle.kts +++ b/android/core/ui/build.gradle.kts @@ -38,5 +38,5 @@ dependencies { api(libs.navigation.fragment.ktx) api(libs.navigation.ui.ktx) - implementation(libs.glide) + api(libs.glide) } \ No newline at end of file diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt index 8489ec3..0228058 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt @@ -3,10 +3,38 @@ package com.ohdodok.catchytape.feature.upload import android.R import android.widget.ArrayAdapter import android.widget.AutoCompleteTextView +import android.widget.Button +import android.widget.ImageView +import androidx.core.view.isVisible import androidx.databinding.BindingAdapter +import com.bumptech.glide.Glide +import com.google.android.material.progressindicator.LinearProgressIndicator @BindingAdapter("list") fun AutoCompleteTextView.setAdapter(list: List) { val adapter = ArrayAdapter(this.context, R.layout.simple_list_item_1, list) setAdapter(adapter) +} + +@BindingAdapter("visible") +fun LinearProgressIndicator.setVisible(uiState: UploadUiState) { + isVisible = uiState.audioState is InputState.Loading || uiState.imageState is InputState.Loading +} + +@BindingAdapter("completeBtnEnable") +fun Button.setCompleteBtnEnable(uiState: UploadUiState) { + isEnabled = + uiState.audioState is InputState.Success + && uiState.imageState is InputState.Success + && uiState.titleState is InputState.Success + && uiState.genreState is InputState.Success +} + +@BindingAdapter("uploadedThumbnail") +fun ImageView.bindUrl(uiState: UploadUiState) { + if (uiState.imageState is InputState.Success) { + Glide.with(this) + .load(uiState.imageState.value) + .into(this) + } } \ No newline at end of file diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 232ef88..8ddda13 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -6,42 +6,24 @@ import dagger.hilt.android.lifecycle.HiltViewModel import java.io.File import javax.inject.Inject import androidx.lifecycle.viewModelScope -import com.ohdodok.catchytape.core.domain.usecase.GetFileUrlUseCase +import com.ohdodok.catchytape.core.domain.usecase.UploadFileUseCase import com.ohdodok.catchytape.core.domain.usecase.GetMusicGenresUseCase import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.stateIn @HiltViewModel class UploadViewModel @Inject constructor( private val getMusicGenresUseCase: GetMusicGenresUseCase, - private val getFileUrlUseCase: GetFileUrlUseCase + private val uploadFileUseCase: UploadFileUseCase ) : ViewModel() { val musicTitle = MutableStateFlow("") val musicGenre = MutableStateFlow("") - private val _thumbnailUrl: MutableStateFlow = MutableStateFlow("") - val thumbnailUrl = _thumbnailUrl.asStateFlow() - - private val _audioUrl: MutableStateFlow = MutableStateFlow("") - val audioUrl = _audioUrl.asStateFlow() - - val isUploadEnable: StateFlow = - combine(musicTitle, musicGenre, thumbnailUrl, audioUrl) { title, genre, thumbnail, audio -> - title.isNotBlank() - && genre.isNotBlank() - && thumbnail.isNotBlank() - && audio.isNotBlank() - }.stateIn(viewModelScope, SharingStarted.Eagerly, false) - private val _musicGenres: MutableStateFlow> = MutableStateFlow(emptyList()) val musicGenres = _musicGenres.asStateFlow() @@ -50,6 +32,8 @@ class UploadViewModel @Inject constructor( init { fetchGenres() + observeTitle() + observeGenre() } private fun fetchGenres() { @@ -58,33 +42,73 @@ class UploadViewModel @Inject constructor( }.launchIn(viewModelScope) } + private fun observeTitle() { + musicTitle.onEach { + if (it.isEmpty()) { + _uploadUiState.value = uploadUiState.value.copy(titleState = InputState.Empty) + return@onEach + } else { + _uploadUiState.value = + uploadUiState.value.copy(titleState = InputState.Success(value = it)) + } + }.launchIn(viewModelScope) + } + + private fun observeGenre() { + musicGenre.onEach { + if (it.isEmpty()) { + _uploadUiState.value = uploadUiState.value.copy(genreState = InputState.Empty) + return@onEach + } else { + _uploadUiState.value = + uploadUiState.value.copy(genreState = InputState.Success(value = it)) + } + }.launchIn(viewModelScope) + } + fun uploadImage(imageUri: Uri) { - // todo : image 파일을 업로드 한다. - // todo : 반환 값을 uploadedImage에 저장한다. imageUri.path?.let { path -> - getFileUrlUseCase(File(path)).onEach { - _thumbnailUrl.value = it + uploadFileUseCase.getImgUrl(File(path)).onStart { + _uploadUiState.value = uploadUiState.value.copy(imageState = InputState.Loading) + }.catch { + // TODO : 에러 처리 + _uploadUiState.value = + uploadUiState.value.copy(imageState = InputState.Error) + }.onEach { url -> + _uploadUiState.value = + uploadUiState.value.copy(imageState = InputState.Success(value = url)) }.launchIn(viewModelScope) } } fun uploadAudio(audioUri: Uri) { - // todo : audio 파일을 업로드 한다. audioUri.path?.let { path -> - getFileUrlUseCase(File(path)).onEach { - _uploadUiState.value = uploadUiState.value.copy(isAudioLoading = false) - _audioUrl.value = it - }.onStart { - _uploadUiState.value = uploadUiState.value.copy(isAudioLoading = true) + uploadFileUseCase.getAudioUrl(File(path)).onStart { + _uploadUiState.value = uploadUiState.value.copy(audioState = InputState.Loading) }.catch { - _uploadUiState.value = uploadUiState.value.copy(isAudioLoading = false) + // TODO : 에러 처리 + _uploadUiState.value = + uploadUiState.value.copy(audioState = InputState.Error) + }.onEach { + _uploadUiState.value = + uploadUiState.value.copy(audioState = InputState.Success(value = it)) }.launchIn(viewModelScope) } } - } -data class UploadUiState ( - val isAudioLoading: Boolean = false, +data class UploadUiState( + val audioState: InputState = InputState.Empty, + val imageState: InputState = InputState.Empty, + val titleState: InputState = InputState.Empty, + val genreState: InputState = InputState.Empty ) +sealed class InputState { + data object Empty : InputState() + + data object Loading : InputState() + data class Success(val value: String) : InputState() + data object Error: InputState() +} + diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index bd1bf34..022118f 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -9,6 +9,7 @@ + + android:text="@string/complete" + app:completeBtnEnable="@{viewModel.uploadUiState}" /> @@ -43,10 +44,10 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:indeterminate="true" - android:visibility="@{viewModel.uploadUiState.audioLoading ? View.VISIBLE : View.GONE}" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/tb_upload" /> + app:layout_constraintTop_toBottomOf="@id/tb_upload" + app:visible="@{viewModel.uploadUiState}" /> + app:uploadedThumbnail="@{viewModel.uploadUiState}" /> Date: Wed, 22 Nov 2023 19:38:06 +0900 Subject: [PATCH 10/15] =?UTF-8?q?feat=20:=20camera=20icon=20visible=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ohdodok/catchytape/feature/upload/BindingAdapter.kt | 7 +++++++ .../feature/upload/src/main/res/layout/fragment_upload.xml | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt index 0228058..bc8da08 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt @@ -1,9 +1,11 @@ package com.ohdodok.catchytape.feature.upload import android.R +import android.graphics.drawable.Drawable import android.widget.ArrayAdapter import android.widget.AutoCompleteTextView import android.widget.Button +import android.widget.ImageButton import android.widget.ImageView import androidx.core.view.isVisible import androidx.databinding.BindingAdapter @@ -37,4 +39,9 @@ fun ImageView.bindUrl(uiState: UploadUiState) { .load(uiState.imageState.value) .into(this) } +} + +@BindingAdapter("visible") +fun ImageView.setVisible(uiState: UploadUiState) { + isVisible = uiState.imageState is InputState.Empty } \ No newline at end of file diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index 022118f..5257c1d 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -6,6 +6,10 @@ + + @@ -77,7 +81,8 @@ android:layout_height="48dp" android:layout_gravity="center" android:importantForAccessibility="no" - android:src="@drawable/ic_camera" /> + android:src="@drawable/ic_camera" + app:visible="@{viewModel.uploadUiState}" /> From 399ba9d9d6055d631e80a2c126bc134fd50aed96 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 19:40:12 +0900 Subject: [PATCH 11/15] =?UTF-8?q?chore=20:=20=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20import=20=EB=AC=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../upload/src/main/res/layout/fragment_upload.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index 5257c1d..6d84b39 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -3,17 +3,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> - - - - - - Date: Wed, 22 Nov 2023 20:05:51 +0900 Subject: [PATCH 12/15] =?UTF-8?q?feat=20:=20empty=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/upload/BindingAdapter.kt | 19 +++------ .../feature/upload/UploadViewModel.kt | 40 +++++++++---------- .../src/main/res/layout/fragment_upload.xml | 7 +++- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt index bc8da08..b3dc905 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt @@ -1,11 +1,9 @@ package com.ohdodok.catchytape.feature.upload import android.R -import android.graphics.drawable.Drawable import android.widget.ArrayAdapter import android.widget.AutoCompleteTextView import android.widget.Button -import android.widget.ImageButton import android.widget.ImageView import androidx.core.view.isVisible import androidx.databinding.BindingAdapter @@ -20,28 +18,23 @@ fun AutoCompleteTextView.setAdapter(list: List) { @BindingAdapter("visible") fun LinearProgressIndicator.setVisible(uiState: UploadUiState) { - isVisible = uiState.audioState is InputState.Loading || uiState.imageState is InputState.Loading + isVisible = uiState.audioState is UploadInputState.Loading || uiState.imageState is UploadInputState.Loading } @BindingAdapter("completeBtnEnable") fun Button.setCompleteBtnEnable(uiState: UploadUiState) { isEnabled = - uiState.audioState is InputState.Success - && uiState.imageState is InputState.Success - && uiState.titleState is InputState.Success - && uiState.genreState is InputState.Success + uiState.audioState is UploadInputState.Success + && uiState.imageState is UploadInputState.Success + && uiState.titleState is UploadInputState.Success + && uiState.genreState is UploadInputState.Success } @BindingAdapter("uploadedThumbnail") fun ImageView.bindUrl(uiState: UploadUiState) { - if (uiState.imageState is InputState.Success) { + if (uiState.imageState is UploadInputState.Success) { Glide.with(this) .load(uiState.imageState.value) .into(this) } -} - -@BindingAdapter("visible") -fun ImageView.setVisible(uiState: UploadUiState) { - isVisible = uiState.imageState is InputState.Empty } \ No newline at end of file diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 8ddda13..7053bc8 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -45,11 +45,11 @@ class UploadViewModel @Inject constructor( private fun observeTitle() { musicTitle.onEach { if (it.isEmpty()) { - _uploadUiState.value = uploadUiState.value.copy(titleState = InputState.Empty) + _uploadUiState.value = uploadUiState.value.copy(titleState = null) return@onEach } else { _uploadUiState.value = - uploadUiState.value.copy(titleState = InputState.Success(value = it)) + uploadUiState.value.copy(titleState = UploadInputState.Success(value = it)) } }.launchIn(viewModelScope) } @@ -57,11 +57,11 @@ class UploadViewModel @Inject constructor( private fun observeGenre() { musicGenre.onEach { if (it.isEmpty()) { - _uploadUiState.value = uploadUiState.value.copy(genreState = InputState.Empty) + _uploadUiState.value = uploadUiState.value.copy(genreState = null) return@onEach } else { _uploadUiState.value = - uploadUiState.value.copy(genreState = InputState.Success(value = it)) + uploadUiState.value.copy(genreState = UploadInputState.Success(value = it)) } }.launchIn(viewModelScope) } @@ -69,14 +69,15 @@ class UploadViewModel @Inject constructor( fun uploadImage(imageUri: Uri) { imageUri.path?.let { path -> uploadFileUseCase.getImgUrl(File(path)).onStart { - _uploadUiState.value = uploadUiState.value.copy(imageState = InputState.Loading) + _uploadUiState.value = + uploadUiState.value.copy(imageState = UploadInputState.Loading) }.catch { // TODO : 에러 처리 _uploadUiState.value = - uploadUiState.value.copy(imageState = InputState.Error) + uploadUiState.value.copy(imageState = UploadInputState.Error) }.onEach { url -> _uploadUiState.value = - uploadUiState.value.copy(imageState = InputState.Success(value = url)) + uploadUiState.value.copy(imageState = UploadInputState.Success(value = url)) }.launchIn(viewModelScope) } } @@ -84,31 +85,30 @@ class UploadViewModel @Inject constructor( fun uploadAudio(audioUri: Uri) { audioUri.path?.let { path -> uploadFileUseCase.getAudioUrl(File(path)).onStart { - _uploadUiState.value = uploadUiState.value.copy(audioState = InputState.Loading) + _uploadUiState.value = + uploadUiState.value.copy(audioState = UploadInputState.Loading) }.catch { // TODO : 에러 처리 _uploadUiState.value = - uploadUiState.value.copy(audioState = InputState.Error) + uploadUiState.value.copy(audioState = UploadInputState.Error) }.onEach { _uploadUiState.value = - uploadUiState.value.copy(audioState = InputState.Success(value = it)) + uploadUiState.value.copy(audioState = UploadInputState.Success(value = it)) }.launchIn(viewModelScope) } } } data class UploadUiState( - val audioState: InputState = InputState.Empty, - val imageState: InputState = InputState.Empty, - val titleState: InputState = InputState.Empty, - val genreState: InputState = InputState.Empty + val audioState: UploadInputState? = null, + val imageState: UploadInputState? = null, + val titleState: UploadInputState? = null, + val genreState: UploadInputState? = null ) -sealed class InputState { - data object Empty : InputState() - - data object Loading : InputState() - data class Success(val value: String) : InputState() - data object Error: InputState() +sealed class UploadInputState { + data object Loading : UploadInputState() + data class Success(val value: String) : UploadInputState() + data object Error : UploadInputState() } diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index 6d84b39..518be9c 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -3,6 +3,11 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + + + @@ -74,7 +79,7 @@ android:layout_gravity="center" android:importantForAccessibility="no" android:src="@drawable/ic_camera" - app:visible="@{viewModel.uploadUiState}" /> + app:visibility="@{viewModel.uploadUiState.imageState == null ? view.VISIBLE : view.GONE}" /> From 3af03408736830c3c1f317ecd1e035d6b2f7a2b9 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 21:11:32 +0900 Subject: [PATCH 13/15] =?UTF-8?q?feat=20:=20file=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/usecase/UploadMusicUseCase.kt | 13 ++ .../catchytape/core/ui/BindingAdapter.kt | 10 +- .../catchytape/core/ui/BindingAdapters.kt | 12 -- .../feature/upload/BindingAdapter.kt | 28 ----- .../feature/upload/UploadViewModel.kt | 115 +++++++++--------- .../src/main/res/layout/fragment_upload.xml | 10 +- 6 files changed, 85 insertions(+), 103 deletions(-) create mode 100644 android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadMusicUseCase.kt delete mode 100644 android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt diff --git a/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadMusicUseCase.kt b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadMusicUseCase.kt new file mode 100644 index 0000000..c6a94dd --- /dev/null +++ b/android/core/domain/src/main/java/com/ohdodok/catchytape/core/domain/usecase/UploadMusicUseCase.kt @@ -0,0 +1,13 @@ +package com.ohdodok.catchytape.core.domain.usecase + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class UploadMusicUseCase @Inject constructor() { + + operator fun invoke(imgUrl: String, audioUrl: String, title: String, genre: String): Flow = flow { + // todo : 서버에 업로드 + emit(Unit) + } +} \ No newline at end of file diff --git a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapter.kt b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapter.kt index 8306400..54821fa 100644 --- a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapter.kt +++ b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapter.kt @@ -1,13 +1,21 @@ package com.ohdodok.catchytape.core.ui +import android.widget.ImageView import androidx.databinding.BindingAdapter import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView - +import com.bumptech.glide.Glide @BindingAdapter("submitList") fun RecyclerView.bindItems(items: List) { val adapter = this.adapter ?: return val listAdapter: ListAdapter = adapter as ListAdapter listAdapter.submitList(items) +} + +@BindingAdapter("imgUrl") +fun ImageView.bindImg(url: String) { + Glide.with(this.context) + .load(url) + .into(this) } \ No newline at end of file diff --git a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt b/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt deleted file mode 100644 index fe02a20..0000000 --- a/android/core/ui/src/main/java/com/ohdodok/catchytape/core/ui/BindingAdapters.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.ohdodok.catchytape.core.ui - -import android.widget.ImageView -import androidx.databinding.BindingAdapter -import com.bumptech.glide.Glide - -@BindingAdapter("imageUrl") -fun ImageView.bindImg(url: String) { - Glide.with(this.context) - .load(url) - .into(this) -} \ No newline at end of file diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt index b3dc905..8489ec3 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/BindingAdapter.kt @@ -3,38 +3,10 @@ package com.ohdodok.catchytape.feature.upload import android.R import android.widget.ArrayAdapter import android.widget.AutoCompleteTextView -import android.widget.Button -import android.widget.ImageView -import androidx.core.view.isVisible import androidx.databinding.BindingAdapter -import com.bumptech.glide.Glide -import com.google.android.material.progressindicator.LinearProgressIndicator @BindingAdapter("list") fun AutoCompleteTextView.setAdapter(list: List) { val adapter = ArrayAdapter(this.context, R.layout.simple_list_item_1, list) setAdapter(adapter) -} - -@BindingAdapter("visible") -fun LinearProgressIndicator.setVisible(uiState: UploadUiState) { - isVisible = uiState.audioState is UploadInputState.Loading || uiState.imageState is UploadInputState.Loading -} - -@BindingAdapter("completeBtnEnable") -fun Button.setCompleteBtnEnable(uiState: UploadUiState) { - isEnabled = - uiState.audioState is UploadInputState.Success - && uiState.imageState is UploadInputState.Success - && uiState.titleState is UploadInputState.Success - && uiState.genreState is UploadInputState.Success -} - -@BindingAdapter("uploadedThumbnail") -fun ImageView.bindUrl(uiState: UploadUiState) { - if (uiState.imageState is UploadInputState.Success) { - Glide.with(this) - .load(uiState.imageState.value) - .into(this) - } } \ No newline at end of file diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 7053bc8..7e4848f 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -8,32 +8,56 @@ import javax.inject.Inject import androidx.lifecycle.viewModelScope import com.ohdodok.catchytape.core.domain.usecase.UploadFileUseCase import com.ohdodok.catchytape.core.domain.usecase.GetMusicGenresUseCase +import com.ohdodok.catchytape.core.domain.usecase.UploadMusicUseCase import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn @HiltViewModel class UploadViewModel @Inject constructor( private val getMusicGenresUseCase: GetMusicGenresUseCase, - private val uploadFileUseCase: UploadFileUseCase + private val uploadFileUseCase: UploadFileUseCase, + private val uploadMusicUseCase: UploadMusicUseCase ) : ViewModel() { val musicTitle = MutableStateFlow("") val musicGenre = MutableStateFlow("") + private val _imageState: MutableStateFlow = MutableStateFlow(UploadedFileState()) + val imageState = _imageState.asStateFlow() + + private val _audioState: MutableStateFlow = MutableStateFlow(UploadedFileState()) + val audioState = _audioState.asStateFlow() + + val isLoading: StateFlow = combine(imageState, audioState) { imageState, audioState -> + imageState.isLoading || audioState.isLoading + }.stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = false + ) + + val isUploadEnable: StateFlow = + combine(musicTitle, musicGenre, imageState, audioState + ) { title, genre, imageState, audioState -> + title.isNotBlank() + && genre.isNotBlank() + && imageState.url.isNotBlank() + && audioState.url.isNotBlank() + }.stateIn(viewModelScope, SharingStarted.Eagerly, false) + private val _musicGenres: MutableStateFlow> = MutableStateFlow(emptyList()) val musicGenres = _musicGenres.asStateFlow() - private val _uploadUiState: MutableStateFlow = MutableStateFlow(UploadUiState()) - val uploadUiState = _uploadUiState.asStateFlow() - init { fetchGenres() - observeTitle() - observeGenre() } private fun fetchGenres() { @@ -42,73 +66,50 @@ class UploadViewModel @Inject constructor( }.launchIn(viewModelScope) } - private fun observeTitle() { - musicTitle.onEach { - if (it.isEmpty()) { - _uploadUiState.value = uploadUiState.value.copy(titleState = null) - return@onEach - } else { - _uploadUiState.value = - uploadUiState.value.copy(titleState = UploadInputState.Success(value = it)) - } - }.launchIn(viewModelScope) - } - - private fun observeGenre() { - musicGenre.onEach { - if (it.isEmpty()) { - _uploadUiState.value = uploadUiState.value.copy(genreState = null) - return@onEach - } else { - _uploadUiState.value = - uploadUiState.value.copy(genreState = UploadInputState.Success(value = it)) - } - }.launchIn(viewModelScope) - } - fun uploadImage(imageUri: Uri) { imageUri.path?.let { path -> - uploadFileUseCase.getImgUrl(File(path)).onStart { - _uploadUiState.value = - uploadUiState.value.copy(imageState = UploadInputState.Loading) + uploadFileUseCase.getImgUrl(File(path)).onEach { url -> + _imageState.value = imageState.value.copy(isLoading = false, url = url) + }.onStart { + _imageState.value = imageState.value.copy(isLoading = true) }.catch { // TODO : 에러 처리 - _uploadUiState.value = - uploadUiState.value.copy(imageState = UploadInputState.Error) - }.onEach { url -> - _uploadUiState.value = - uploadUiState.value.copy(imageState = UploadInputState.Success(value = url)) + _imageState.value = imageState.value.copy(isLoading = false) }.launchIn(viewModelScope) } } fun uploadAudio(audioUri: Uri) { audioUri.path?.let { path -> - uploadFileUseCase.getAudioUrl(File(path)).onStart { - _uploadUiState.value = - uploadUiState.value.copy(audioState = UploadInputState.Loading) + uploadFileUseCase.getAudioUrl(File(path)).onEach { + _audioState.value = audioState.value.copy(isLoading = false, url = it) + }.onStart { + _audioState.value = audioState.value.copy(isLoading = true) }.catch { // TODO : 에러 처리 - _uploadUiState.value = - uploadUiState.value.copy(audioState = UploadInputState.Error) - }.onEach { - _uploadUiState.value = - uploadUiState.value.copy(audioState = UploadInputState.Success(value = it)) + _audioState.value = audioState.value.copy(isLoading = false) + }.launchIn(viewModelScope) + } + } + + fun uploadMusic() { + if (isUploadEnable.value) { + uploadMusicUseCase( + imgUrl = imageState.value.url, + audioUrl = audioState.value.url, + title = musicTitle.value, + genre = musicGenre.value + ).onEach { + // TODO : 업로드 성공 + }.catch { + // TODO : 업로드 실패 }.launchIn(viewModelScope) } } } -data class UploadUiState( - val audioState: UploadInputState? = null, - val imageState: UploadInputState? = null, - val titleState: UploadInputState? = null, - val genreState: UploadInputState? = null +data class UploadedFileState( + val isLoading: Boolean = false, + val url: String = "" ) -sealed class UploadInputState { - data object Loading : UploadInputState() - data class Success(val value: String) : UploadInputState() - data object Error : UploadInputState() -} - diff --git a/android/feature/upload/src/main/res/layout/fragment_upload.xml b/android/feature/upload/src/main/res/layout/fragment_upload.xml index 518be9c..9c988c5 100644 --- a/android/feature/upload/src/main/res/layout/fragment_upload.xml +++ b/android/feature/upload/src/main/res/layout/fragment_upload.xml @@ -35,8 +35,8 @@ android:layout_gravity="end|center_vertical" android:layout_marginEnd="@dimen/margin_horizontal" android:background="@android:color/transparent" - android:text="@string/complete" - app:completeBtnEnable="@{viewModel.uploadUiState}" /> + android:enabled="@{viewModel.isUploadEnable}" + android:text="@string/complete" /> @@ -48,7 +48,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tb_upload" - app:visible="@{viewModel.uploadUiState}" /> + android:visibility="@{viewModel.isLoading ? view.VISIBLE : view.GONE}" /> + app:imgUrl="@{viewModel.imageState.url}" /> + app:visibility="@{viewModel.imageState.url.empty ? view.VISIBLE : view.GONE}" /> From d577bd8ed4328da23d1a8b0d95f86044a68d1ba4 Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 23:03:36 +0900 Subject: [PATCH 14/15] =?UTF-8?q?feat=20:=20flow=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EC=88=9C=EC=84=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/upload/UploadViewModel.kt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 7e4848f..8b574e2 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn @@ -68,12 +69,11 @@ class UploadViewModel @Inject constructor( fun uploadImage(imageUri: Uri) { imageUri.path?.let { path -> - uploadFileUseCase.getImgUrl(File(path)).onEach { url -> - _imageState.value = imageState.value.copy(isLoading = false, url = url) - }.onStart { + uploadFileUseCase.getImgUrl(File(path)).onStart { _imageState.value = imageState.value.copy(isLoading = true) - }.catch { - // TODO : 에러 처리 + }.onEach { url -> + _imageState.value = imageState.value.copy(url = url) + }.onCompletion { _imageState.value = imageState.value.copy(isLoading = false) }.launchIn(viewModelScope) } @@ -81,12 +81,11 @@ class UploadViewModel @Inject constructor( fun uploadAudio(audioUri: Uri) { audioUri.path?.let { path -> - uploadFileUseCase.getAudioUrl(File(path)).onEach { - _audioState.value = audioState.value.copy(isLoading = false, url = it) - }.onStart { + uploadFileUseCase.getAudioUrl(File(path)).onStart { _audioState.value = audioState.value.copy(isLoading = true) - }.catch { - // TODO : 에러 처리 + }.onEach { url -> + _audioState.value = audioState.value.copy(url = url) + }.onCompletion { _audioState.value = audioState.value.copy(isLoading = false) }.launchIn(viewModelScope) } From 1dfbf3b1657d76112e28b37761800f1bed12789c Mon Sep 17 00:00:00 2001 From: youlalala Date: Wed, 22 Nov 2023 23:18:47 +0900 Subject: [PATCH 15/15] =?UTF-8?q?refactor=20:=20file=20=EB=B3=80=ED=99=98?= =?UTF-8?q?=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/upload/UploadFragment.kt | 5 ++- .../feature/upload/UploadViewModel.kt | 45 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt index 3253885..b82c3aa 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadFragment.kt @@ -12,6 +12,7 @@ import com.ohdodok.catchytape.catchytape.upload.R import com.ohdodok.catchytape.catchytape.upload.databinding.FragmentUploadBinding import com.ohdodok.catchytape.core.ui.BaseFragment import dagger.hilt.android.AndroidEntryPoint +import java.io.File @AndroidEntryPoint class UploadFragment : BaseFragment(R.layout.fragment_upload) { @@ -19,14 +20,14 @@ class UploadFragment : BaseFragment(R.layout.fragment_upl private val imagePickerLauncher = registerForActivityResult(PickVisualMedia()) { uri -> if (uri == null) return@registerForActivityResult - viewModel.uploadImage(uri) + uri.path?.let { viewModel.uploadImage(File(it)) } } private val filePickerLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> if (uri == null) return@registerForActivityResult binding.btnFile.text = getFileName(uri) - viewModel.uploadAudio(uri) + uri.path?.let { viewModel.uploadAudio(File(it)) } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt index 8b574e2..e8b66ad 100644 --- a/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt +++ b/android/feature/upload/src/main/java/com/ohdodok/catchytape/feature/upload/UploadViewModel.kt @@ -31,10 +31,12 @@ class UploadViewModel @Inject constructor( val musicTitle = MutableStateFlow("") val musicGenre = MutableStateFlow("") - private val _imageState: MutableStateFlow = MutableStateFlow(UploadedFileState()) + private val _imageState: MutableStateFlow = + MutableStateFlow(UploadedFileState()) val imageState = _imageState.asStateFlow() - private val _audioState: MutableStateFlow = MutableStateFlow(UploadedFileState()) + private val _audioState: MutableStateFlow = + MutableStateFlow(UploadedFileState()) val audioState = _audioState.asStateFlow() val isLoading: StateFlow = combine(imageState, audioState) { imageState, audioState -> @@ -46,7 +48,8 @@ class UploadViewModel @Inject constructor( ) val isUploadEnable: StateFlow = - combine(musicTitle, musicGenre, imageState, audioState + combine( + musicTitle, musicGenre, imageState, audioState ) { title, genre, imageState, audioState -> title.isNotBlank() && genre.isNotBlank() @@ -67,28 +70,24 @@ class UploadViewModel @Inject constructor( }.launchIn(viewModelScope) } - fun uploadImage(imageUri: Uri) { - imageUri.path?.let { path -> - uploadFileUseCase.getImgUrl(File(path)).onStart { - _imageState.value = imageState.value.copy(isLoading = true) - }.onEach { url -> - _imageState.value = imageState.value.copy(url = url) - }.onCompletion { - _imageState.value = imageState.value.copy(isLoading = false) - }.launchIn(viewModelScope) - } + fun uploadImage(imageFile: File) { + uploadFileUseCase.getImgUrl(imageFile).onStart { + _imageState.value = imageState.value.copy(isLoading = true) + }.onEach { url -> + _imageState.value = imageState.value.copy(url = url) + }.onCompletion { + _imageState.value = imageState.value.copy(isLoading = false) + }.launchIn(viewModelScope) } - fun uploadAudio(audioUri: Uri) { - audioUri.path?.let { path -> - uploadFileUseCase.getAudioUrl(File(path)).onStart { - _audioState.value = audioState.value.copy(isLoading = true) - }.onEach { url -> - _audioState.value = audioState.value.copy(url = url) - }.onCompletion { - _audioState.value = audioState.value.copy(isLoading = false) - }.launchIn(viewModelScope) - } + fun uploadAudio(audioFile: File) { + uploadFileUseCase.getAudioUrl(audioFile).onStart { + _audioState.value = audioState.value.copy(isLoading = true) + }.onEach { url -> + _audioState.value = audioState.value.copy(url = url) + }.onCompletion { + _audioState.value = audioState.value.copy(isLoading = false) + }.launchIn(viewModelScope) } fun uploadMusic() {