From e6c5692b7167f61f309d0baac7abd42922bd131f Mon Sep 17 00:00:00 2001 From: EvergreenTree97 Date: Mon, 30 Sep 2024 13:36:44 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EA=B0=A4=EB=9F=AC=EB=A6=AC=EC=97=90=EC=84=9C=20=EB=B6=88?= =?UTF-8?q?=EB=9F=AC=EC=98=A4=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../team/ppac/navigation/FarmemeNavHost.kt | 3 +- .../data/repository/MemeRepositoryImpl.kt | 9 ++++++ .../ppac/domain/repository/MemeRepository.kt | 6 ++++ .../ppac/domain/usecase/UpLoadImageUseCase.kt | 11 +++++++ .../recommendation/RecommendationRoute.kt | 8 +++++ .../recommendation/RecommendationScreen.kt | 3 +- .../recommendation/RecommendationViewModel.kt | 4 +++ .../mvi/RecommendationIntent.kt | 2 ++ .../mvi/RecommendationSideEffect.kt | 2 ++ .../navigation/RecommendationNavigation.kt | 4 ++- .../java/team/ppac/register/RegisterRoute.kt | 1 + .../java/team/ppac/register/RegisterScreen.kt | 17 ++++++++-- .../team/ppac/register/RegisterViewModel.kt | 10 ++++-- .../register/component/RegisterImageArea.kt | 32 ++++++++++++++----- .../team/ppac/register/mvi/RegisterIntent.kt | 2 +- .../team/ppac/register/mvi/RegisterUiState.kt | 4 ++- 16 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 core/domain/src/main/java/team/ppac/domain/usecase/UpLoadImageUseCase.kt diff --git a/app/src/main/java/team/ppac/navigation/FarmemeNavHost.kt b/app/src/main/java/team/ppac/navigation/FarmemeNavHost.kt index 2d7f3ab5..da492dc9 100644 --- a/app/src/main/java/team/ppac/navigation/FarmemeNavHost.kt +++ b/app/src/main/java/team/ppac/navigation/FarmemeNavHost.kt @@ -37,7 +37,8 @@ fun FarmemeNavHost( exitTransition = { ExitTransition.None }, ) { recommendationScreen( - analyticsHelper = analyticsHelper + analyticsHelper = analyticsHelper, + navigateToRegister = navigateToRegister, ) searchScreen( analyticsHelper = analyticsHelper, diff --git a/core/data/src/main/java/team/ppac/data/repository/MemeRepositoryImpl.kt b/core/data/src/main/java/team/ppac/data/repository/MemeRepositoryImpl.kt index 149ece18..f8b44c6e 100644 --- a/core/data/src/main/java/team/ppac/data/repository/MemeRepositoryImpl.kt +++ b/core/data/src/main/java/team/ppac/data/repository/MemeRepositoryImpl.kt @@ -71,6 +71,15 @@ internal class MemeRepositoryImpl @Inject constructor( override val savedMemeEventFlow: Flow get() = _savedMemeEventFlow + override suspend fun uploadMeme( + memeId: String, + memeImageUri: String, + memeTitle: String, + memeSource: String, + ): Boolean { + return false // TODO + } + override suspend fun emitRefreshEvent() { _savedMemeEventFlow.emit(SavedMemeEvent.Refresh) } diff --git a/core/domain/src/main/java/team/ppac/domain/repository/MemeRepository.kt b/core/domain/src/main/java/team/ppac/domain/repository/MemeRepository.kt index 5f5821c2..fc3b3a82 100644 --- a/core/domain/src/main/java/team/ppac/domain/repository/MemeRepository.kt +++ b/core/domain/src/main/java/team/ppac/domain/repository/MemeRepository.kt @@ -23,6 +23,12 @@ interface MemeRepository { suspend fun emitRefreshEvent() val savedMemeEventFlow: Flow + suspend fun uploadMeme( + memeId: String, + memeImageUri: String, + memeTitle: String, + memeSource: String, + ): Boolean } sealed class SavedMemeEvent { diff --git a/core/domain/src/main/java/team/ppac/domain/usecase/UpLoadImageUseCase.kt b/core/domain/src/main/java/team/ppac/domain/usecase/UpLoadImageUseCase.kt new file mode 100644 index 00000000..84cb673b --- /dev/null +++ b/core/domain/src/main/java/team/ppac/domain/usecase/UpLoadImageUseCase.kt @@ -0,0 +1,11 @@ +package team.ppac.domain.usecase + +interface UpLoadImageUseCase { + suspend operator fun invoke(uri: String) +} + +internal class UpLoadImageUseCaseImpl : UpLoadImageUseCase { + override suspend fun invoke(uri: String) { + + } +} \ No newline at end of file diff --git a/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationRoute.kt b/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationRoute.kt index 32d5967e..191f5232 100644 --- a/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationRoute.kt +++ b/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationRoute.kt @@ -30,6 +30,7 @@ import team.ppac.recommendation.mvi.RecommendationSideEffect @Composable internal fun RecommendationRoute( analyticsHelper: AnalyticsHelper, + navigateToRegister: () -> Unit, viewModel: RecommendationViewModel = hiltViewModel(), ) { val context = LocalContext.current @@ -138,6 +139,10 @@ internal fun RecommendationRoute( screen = ScreenType.RECOMMENDATION, ) } + + RecommendationSideEffect.NavigateToRegister -> { + navigateToRegister() + } } } } @@ -169,6 +174,9 @@ internal fun RecommendationRoute( memeBitmap[index] = bitmap }, onActionButtonsIntentClick = viewModel::intent, + onUpload = { + viewModel.intent(RecommendationIntent.ClickUpload) + } ) } } \ No newline at end of file diff --git a/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationScreen.kt b/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationScreen.kt index 41d669ac..55c46c93 100644 --- a/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationScreen.kt +++ b/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationScreen.kt @@ -77,6 +77,7 @@ internal fun RecommendationScreen( onRetryClick: () -> Unit, onLoadMeme: (Int, Bitmap) -> Unit, onScrollPager: (Int, Meme) -> Unit, + onUpload: () -> Unit, onActionButtonsIntentClick: (RecommendationIntent.ClickButton) -> Unit, ) { val heroModulePagerState = rememberPagerState { state.thisWeekMemes.size } @@ -151,7 +152,7 @@ internal fun RecommendationScreen( } else { UploadButton( onClick = { - + onUpload() } ) } diff --git a/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationViewModel.kt b/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationViewModel.kt index c7856496..e493199f 100644 --- a/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationViewModel.kt +++ b/feature/recommendation/src/main/java/team/ppac/recommendation/RecommendationViewModel.kt @@ -139,6 +139,10 @@ class RecommendationViewModel @Inject constructor( copy(isError = false) } } + + RecommendationIntent.ClickUpload -> { + postSideEffect(RecommendationSideEffect.NavigateToRegister) + } } } diff --git a/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationIntent.kt b/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationIntent.kt index 4bb16c7f..3a7b0770 100644 --- a/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationIntent.kt +++ b/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationIntent.kt @@ -6,6 +6,8 @@ import team.ppac.domain.model.Meme sealed interface RecommendationIntent : UiIntent { data object Init : RecommendationIntent data object PullRefresh : RecommendationIntent + data object ClickUpload : RecommendationIntent + data class MovePage( val meme: Meme, val currentPage: Int, diff --git a/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationSideEffect.kt b/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationSideEffect.kt index eca1df4b..6a7a3706 100644 --- a/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationSideEffect.kt +++ b/feature/recommendation/src/main/java/team/ppac/recommendation/mvi/RecommendationSideEffect.kt @@ -8,6 +8,8 @@ sealed interface RecommendationSideEffect : UiSideEffect { data class CopyClipBoard(val selectedMemeIndex: Int) : RecommendationSideEffect data class ShareLink(val memeId: String) : RecommendationSideEffect data object LogHashTagsClicked : RecommendationSideEffect + data object NavigateToRegister : RecommendationSideEffect + data class LogSaveMeme(val meme: Meme) : RecommendationSideEffect data class LogSaveMemeCancel(val meme: Meme) : RecommendationSideEffect } \ No newline at end of file diff --git a/feature/recommendation/src/main/java/team/ppac/recommendation/navigation/RecommendationNavigation.kt b/feature/recommendation/src/main/java/team/ppac/recommendation/navigation/RecommendationNavigation.kt index 90d9f116..97dc49ae 100644 --- a/feature/recommendation/src/main/java/team/ppac/recommendation/navigation/RecommendationNavigation.kt +++ b/feature/recommendation/src/main/java/team/ppac/recommendation/navigation/RecommendationNavigation.kt @@ -13,12 +13,14 @@ fun NavController.navigateToRecommendation(navOptions: NavOptions) = navigate(RE fun NavGraphBuilder.recommendationScreen( analyticsHelper: AnalyticsHelper, + navigateToRegister: () -> Unit ) { composable( route = RECOMMENDATION_ROUTE ) { RecommendationRoute( - analyticsHelper = analyticsHelper + analyticsHelper = analyticsHelper, + navigateToRegister = navigateToRegister, ) } } \ No newline at end of file diff --git a/feature/register/src/main/java/team/ppac/register/RegisterRoute.kt b/feature/register/src/main/java/team/ppac/register/RegisterRoute.kt index fcd4ce6f..64106eee 100644 --- a/feature/register/src/main/java/team/ppac/register/RegisterRoute.kt +++ b/feature/register/src/main/java/team/ppac/register/RegisterRoute.kt @@ -22,6 +22,7 @@ internal fun RegisterRoute( RegisterScreen( uiState = uiState, navigateToBack = navigateToBack, + onIntent = viewModel::intent, ) } } \ No newline at end of file diff --git a/feature/register/src/main/java/team/ppac/register/RegisterScreen.kt b/feature/register/src/main/java/team/ppac/register/RegisterScreen.kt index d3d05894..7aed4eb6 100644 --- a/feature/register/src/main/java/team/ppac/register/RegisterScreen.kt +++ b/feature/register/src/main/java/team/ppac/register/RegisterScreen.kt @@ -1,5 +1,8 @@ package team.ppac.register +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -22,13 +25,21 @@ import team.ppac.register.component.RegisterCategoryContent import team.ppac.register.component.RegisterImageArea import team.ppac.register.component.RegisterInputArea import team.ppac.register.component.RegisterKeywordHeader +import team.ppac.register.mvi.RegisterIntent import team.ppac.register.mvi.RegisterUiState @Composable internal fun RegisterScreen( uiState: RegisterUiState, navigateToBack: () -> Unit, + onIntent: (RegisterIntent) -> Unit, ) { + val imagePicker = + rememberLauncherForActivityResult(contract = ActivityResultContracts.PickVisualMedia()) { uri -> + if (uri != null) { + onIntent(RegisterIntent.SetImageFromGallery(uri.toString())) + } + } FarmemeScaffold( modifier = Modifier.navigationBarsPadding(), topBar = { @@ -48,7 +59,7 @@ internal fun RegisterScreen( modifier = Modifier.padding(bottom = 36.dp), text = "등록하기", enabled = true, - onClick = {}, + onClick = { }, ) } ) { @@ -58,7 +69,8 @@ internal fun RegisterScreen( ) { item { RegisterImageArea( - hasImage = false, + loadImage = { imagePicker.launch(PickVisualMediaRequest(mediaType = ActivityResultContracts.PickVisualMedia.ImageOnly)) }, + imageUri = uiState.imageUri, ) } item { RegisterInputArea() } @@ -86,5 +98,6 @@ private fun RegisterScreenPreview() { RegisterScreen( uiState = RegisterUiState.INITIAL_STATE, navigateToBack = {}, + onIntent = {}, ) } \ No newline at end of file diff --git a/feature/register/src/main/java/team/ppac/register/RegisterViewModel.kt b/feature/register/src/main/java/team/ppac/register/RegisterViewModel.kt index f5006d08..a7715061 100644 --- a/feature/register/src/main/java/team/ppac/register/RegisterViewModel.kt +++ b/feature/register/src/main/java/team/ppac/register/RegisterViewModel.kt @@ -27,8 +27,12 @@ class RegisterViewModel @Inject constructor( } override suspend fun handleIntent(intent: RegisterIntent) { -// when (intent) { -// -// } + when (intent) { + is RegisterIntent.SetImageFromGallery -> { + reduce { + copy(imageUri = intent.uri) + } + } + } } } \ No newline at end of file diff --git a/feature/register/src/main/java/team/ppac/register/component/RegisterImageArea.kt b/feature/register/src/main/java/team/ppac/register/component/RegisterImageArea.kt index a1d03791..4e1f464a 100644 --- a/feature/register/src/main/java/team/ppac/register/component/RegisterImageArea.kt +++ b/feature/register/src/main/java/team/ppac/register/component/RegisterImageArea.kt @@ -13,22 +13,27 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import coil.request.ImageRequest import team.ppac.designsystem.FarmemeTheme import team.ppac.designsystem.component.button.FarmemeCircleButton import team.ppac.designsystem.component.button.FarmemeWeakButton import team.ppac.designsystem.foundation.FarmemeIcon import team.ppac.designsystem.foundation.FarmemeRadius +import team.ppac.designsystem.util.extension.noRippleClickable @Composable internal fun RegisterImageArea( modifier: Modifier = Modifier, - hasImage: Boolean, - loadImage: () -> Unit = {}, + imageUri: String, + loadImage: () -> Unit, ) { val borderColor = - if (hasImage) FarmemeTheme.borderColor.primary else FarmemeTheme.borderColor.tertiary + if (imageUri.isNotEmpty()) FarmemeTheme.borderColor.primary else FarmemeTheme.borderColor.tertiary Box( modifier = modifier @@ -41,10 +46,11 @@ internal fun RegisterImageArea( color = borderColor, shape = FarmemeRadius.Radius20.shape, ) - .background(FarmemeTheme.backgroundColor.assistive), + .background(FarmemeTheme.backgroundColor.assistive) + .noRippleClickable(onClick = loadImage), contentAlignment = Alignment.Center, ) { - if (!hasImage) { + if (imageUri.isEmpty()) { FarmemeWeakButton( text = "이미지 등록", withStar = true, @@ -56,12 +62,20 @@ internal fun RegisterImageArea( } ) } else { - // AsyncImage Box( modifier = Modifier .fillMaxSize() .background(FarmemeTheme.backgroundColor.brandAssistive), ) + AsyncImage( + modifier = Modifier.matchParentSize(), + model = ImageRequest.Builder(LocalContext.current) + .data(imageUri) + .crossfade(true) + .build(), + contentDescription = null, + contentScale = ContentScale.Crop, + ) FarmemeCircleButton( modifier = Modifier .align(Alignment.BottomEnd) @@ -79,10 +93,12 @@ internal fun RegisterImageArea( private fun RegisterImageAreaPreview() { Column { RegisterImageArea( - hasImage = true, + loadImage = {}, + imageUri = "", ) RegisterImageArea( - hasImage = false, + loadImage = {}, + imageUri = "asdf", ) } } \ No newline at end of file diff --git a/feature/register/src/main/java/team/ppac/register/mvi/RegisterIntent.kt b/feature/register/src/main/java/team/ppac/register/mvi/RegisterIntent.kt index 4bab5f60..c7b4cf31 100644 --- a/feature/register/src/main/java/team/ppac/register/mvi/RegisterIntent.kt +++ b/feature/register/src/main/java/team/ppac/register/mvi/RegisterIntent.kt @@ -3,5 +3,5 @@ package team.ppac.register.mvi import team.ppac.common.android.base.UiIntent sealed interface RegisterIntent : UiIntent { - + data class SetImageFromGallery(val uri: String) : RegisterIntent } \ No newline at end of file diff --git a/feature/register/src/main/java/team/ppac/register/mvi/RegisterUiState.kt b/feature/register/src/main/java/team/ppac/register/mvi/RegisterUiState.kt index 85e0f0e4..f181a78e 100644 --- a/feature/register/src/main/java/team/ppac/register/mvi/RegisterUiState.kt +++ b/feature/register/src/main/java/team/ppac/register/mvi/RegisterUiState.kt @@ -8,7 +8,8 @@ import team.ppac.register.model.RegisterCategoryUiModel data class RegisterUiState( val isLoading: Boolean, val isError: Boolean, - val registerCategories: ImmutableList + val registerCategories: ImmutableList, + val imageUri: String, ) : UiState { companion object { @@ -59,6 +60,7 @@ data class RegisterUiState( ), ) ), + imageUri = "" ) } } \ No newline at end of file