diff --git a/data/src/main/java/com/dev/playground/data/data_source/remote/MemoryService.kt b/data/src/main/java/com/dev/playground/data/data_source/remote/MemoryService.kt index 2402f39..9fb6c9c 100644 --- a/data/src/main/java/com/dev/playground/data/data_source/remote/MemoryService.kt +++ b/data/src/main/java/com/dev/playground/data/data_source/remote/MemoryService.kt @@ -12,4 +12,7 @@ interface MemoryService { @POST("memory") suspend fun postMemory(@Body memoryInput: MemoryInput): MemoryData + @DELETE("memory/{id}") + suspend fun deleteMemory(@Path("id") params: Int) + } \ No newline at end of file diff --git a/data/src/main/java/com/dev/playground/data/repository/MemoryRepositoryImpl.kt b/data/src/main/java/com/dev/playground/data/repository/MemoryRepositoryImpl.kt index 9e52f67..6d3808f 100644 --- a/data/src/main/java/com/dev/playground/data/repository/MemoryRepositoryImpl.kt +++ b/data/src/main/java/com/dev/playground/data/repository/MemoryRepositoryImpl.kt @@ -13,4 +13,6 @@ class MemoryRepositoryImpl(private val service: MemoryService) : MemoryRepositor override suspend fun postMemory(params: MemoryInput): Memory = service.postMemory(params).toDomain() + override suspend fun deleteMemory(params: Int) = service.deleteMemory(params) + } \ No newline at end of file diff --git a/domain/src/main/java/com/dev/playground/domain/di/UseCaseModule.kt b/domain/src/main/java/com/dev/playground/domain/di/UseCaseModule.kt index 348bce2..a50e867 100644 --- a/domain/src/main/java/com/dev/playground/domain/di/UseCaseModule.kt +++ b/domain/src/main/java/com/dev/playground/domain/di/UseCaseModule.kt @@ -5,6 +5,7 @@ import com.dev.playground.domain.usecase.login.GetTokenUseCase import com.dev.playground.domain.usecase.login.RemoveKakaoTokenUseCase import com.dev.playground.domain.usecase.login.RequestLoginUseCase import com.dev.playground.domain.usecase.login.SetTokenUseCase +import com.dev.playground.domain.usecase.memory.DeleteMemoryUseCase import com.dev.playground.domain.usecase.memory.GetMemoryListUseCase import com.dev.playground.domain.usecase.memory.PostMemoryUseCase import com.dev.playground.domain.usecase.photo.DeletePhotoUseCase @@ -15,11 +16,16 @@ import org.koin.dsl.module val useCaseModule = module { factory { GetTokenUseCase(get(), get(named(IO))) } factory { SetTokenUseCase(get(), get(named(IO))) } + factory { RemoveKakaoTokenUseCase(get(), get(named(IO))) } factory { RequestLoginUseCase(get(), get(named(IO))) } + factory { GetMemoryListUseCase(get(), get(named(IO))) } factory { PostMemoryUseCase(get(), get(named(IO))) } + factory { DeleteMemoryUseCase(get(), get(named(IO))) } + factory { UploadPhotoUseCase(get(), get(named(IO))) } factory { DeletePhotoUseCase(get(), get(named(IO))) } + factory { GetAddressUseCase(get(), get(named(IO))) } } \ No newline at end of file diff --git a/domain/src/main/java/com/dev/playground/domain/repository/MemoryRepository.kt b/domain/src/main/java/com/dev/playground/domain/repository/MemoryRepository.kt index 6016732..8ab8cf3 100644 --- a/domain/src/main/java/com/dev/playground/domain/repository/MemoryRepository.kt +++ b/domain/src/main/java/com/dev/playground/domain/repository/MemoryRepository.kt @@ -9,4 +9,6 @@ interface MemoryRepository { suspend fun postMemory(params: MemoryInput): Memory + suspend fun deleteMemory(params: Int) + } \ No newline at end of file diff --git a/domain/src/main/java/com/dev/playground/domain/usecase/memory/DeleteMemoryUseCase.kt b/domain/src/main/java/com/dev/playground/domain/usecase/memory/DeleteMemoryUseCase.kt new file mode 100644 index 0000000..fe893e5 --- /dev/null +++ b/domain/src/main/java/com/dev/playground/domain/usecase/memory/DeleteMemoryUseCase.kt @@ -0,0 +1,17 @@ +package com.dev.playground.domain.usecase.memory + +import com.dev.playground.domain.repository.MemoryRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext + +class DeleteMemoryUseCase( + private val repository: MemoryRepository, + private val dispatcher: CoroutineDispatcher +) { + + suspend operator fun invoke(id: Int) = withContext(dispatcher) { + runCatching { + repository.deleteMemory(id) + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/dev/playground/presentation/di/ViewModelModule.kt b/presentation/src/main/java/com/dev/playground/presentation/di/ViewModelModule.kt index 2b0ec3c..5a3dfb2 100644 --- a/presentation/src/main/java/com/dev/playground/presentation/di/ViewModelModule.kt +++ b/presentation/src/main/java/com/dev/playground/presentation/di/ViewModelModule.kt @@ -26,5 +26,10 @@ val viewModelModule = module { getAddressUseCase = get() ) } - viewModel { FeedViewModel(getMemoryListUseCase = get()) } + viewModel { + FeedViewModel( + getMemoryListUseCase = get(), + deleteMemoryUseCase = get() + ) + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/dev/playground/presentation/ui/dialog/DropDialog.kt b/presentation/src/main/java/com/dev/playground/presentation/ui/dialog/DropDialog.kt new file mode 100644 index 0000000..b8b1c9f --- /dev/null +++ b/presentation/src/main/java/com/dev/playground/presentation/ui/dialog/DropDialog.kt @@ -0,0 +1,53 @@ +package com.dev.playground.presentation.ui.dialog + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import androidx.databinding.DataBindingUtil +import com.dev.playground.presentation.R +import com.dev.playground.presentation.databinding.DialogDropBinding + +class DropDialog(context: Context) : Dialog(context) { + + companion object { + private const val EMPTY = "" + } + + private lateinit var binding: DialogDropBinding + + var contentText: String = EMPTY + var leftText: String = EMPTY + var rightText: String = EMPTY + + var onLeftClick: (() -> Unit)? = null + var onRightClick: (() -> Unit)? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.inflate( + LayoutInflater.from(context), + R.layout.dialog_drop, + null, + false + ) + setContentView(binding.root) + initViews() + } + + private fun initViews() = with(binding) { + tvContent.text = contentText + tvLeft.text = leftText + tvRight.text = rightText + + tvLeft.setOnClickListener { + onLeftClick?.invoke() + } + tvRight.setOnClickListener { + onRightClick?.invoke() + } + } + +} + +fun DropDialog.show(action: DropDialog.() -> Unit) = DropDialog(context).apply(action).show() \ No newline at end of file diff --git a/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedContract.kt b/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedContract.kt index 3825241..0496a85 100644 --- a/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedContract.kt +++ b/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedContract.kt @@ -36,14 +36,15 @@ class FeedContract { } } - sealed interface Event : UiEvent { - data class OnClickEdit(val id: Int) : Event - data class OnClickRemove(val id: Int) : Event + sealed class Event(open val id: Int) : UiEvent { + data class OnClickEdit(override val id: Int) : Event(id) + data class OnClickRemove(override val id: Int) : Event(id) + data class OnClickDeleteMemory(override val id: Int) : Event(id) } - sealed interface Effect: UiEffect { - data class ShowEditPage(val id: Int): Effect - data class ShowRemoveDialog(val id: Int): Effect + sealed interface Effect : UiEffect { + data class ShowEditPage(val id: Int) : Effect + data class ShowRemoveDialog(val id: Int) : Effect } } diff --git a/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedFragment.kt b/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedFragment.kt index f461d2f..a9532ba 100644 --- a/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedFragment.kt +++ b/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedFragment.kt @@ -7,8 +7,11 @@ import com.dev.playground.presentation.base.BaseFragment import com.dev.playground.presentation.base.ScrollableScreen import com.dev.playground.presentation.base.SimpleBindingAdapter import com.dev.playground.presentation.databinding.FragmentFeedBinding +import com.dev.playground.presentation.ui.dialog.DropDialog +import com.dev.playground.presentation.ui.dialog.show import com.dev.playground.presentation.ui.feed.FeedContract.Effect.ShowEditPage import com.dev.playground.presentation.ui.feed.FeedContract.Effect.ShowRemoveDialog +import com.dev.playground.presentation.ui.feed.FeedContract.Event.OnClickDeleteMemory import com.dev.playground.presentation.ui.feed.FeedContract.State.Success import com.dev.playground.presentation.util.repeatOnLifecycleState import kotlinx.coroutines.flow.collectLatest @@ -53,7 +56,19 @@ class FeedFragment : BaseFragment(R.layout.fragment_feed), is ShowEditPage -> { } - is ShowRemoveDialog -> { + is ShowRemoveDialog -> context?.let { c -> + DropDialog(c).show { + contentText = getString(R.string.drop_dialog_content_remove_memory) + leftText = getString(R.string.drop_dialog_cancel) + rightText = getString(R.string.drop_dialog_delete) + onLeftClick = { + dismiss() + } + onRightClick = { + setEvent(OnClickDeleteMemory(it.id)) + dismiss() + } + } } } } diff --git a/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedViewModel.kt b/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedViewModel.kt index 15ca28b..167a480 100644 --- a/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedViewModel.kt +++ b/presentation/src/main/java/com/dev/playground/presentation/ui/feed/FeedViewModel.kt @@ -1,6 +1,7 @@ package com.dev.playground.presentation.ui.feed import androidx.lifecycle.viewModelScope +import com.dev.playground.domain.usecase.memory.DeleteMemoryUseCase import com.dev.playground.domain.usecase.memory.GetMemoryListUseCase import com.dev.playground.presentation.base.BaseViewModel import com.dev.playground.presentation.model.toPresentation @@ -14,6 +15,7 @@ import kotlinx.coroutines.launch class FeedViewModel( private val getMemoryListUseCase: GetMemoryListUseCase, + private val deleteMemoryUseCase: DeleteMemoryUseCase, ) : BaseViewModel(Loading) { init { @@ -43,12 +45,22 @@ class FeedViewModel( } } + private fun deleteMemory(id: Int) { + viewModelScope.launch { + deleteMemoryUseCase.invoke(id) + fetch() + } + } + override fun handleEvent(event: Event) { - setEffect { - when (event) { - is OnClickEdit -> ShowEditPage(event.id) - is OnClickRemove -> ShowRemoveDialog(event.id) + when (event) { + is OnClickEdit -> setEffect { + ShowEditPage(event.id) + } + is OnClickRemove -> setEffect { + ShowRemoveDialog(event.id) } + is Event.OnClickDeleteMemory -> deleteMemory(event.id) } } diff --git a/presentation/src/main/res/drawable/ic_warning_lime.xml b/presentation/src/main/res/drawable/ic_warning_lime.xml new file mode 100644 index 0000000..ce5ed64 --- /dev/null +++ b/presentation/src/main/res/drawable/ic_warning_lime.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/presentation/src/main/res/layout/dialog_drop.xml b/presentation/src/main/res/layout/dialog_drop.xml new file mode 100644 index 0000000..36a1e3a --- /dev/null +++ b/presentation/src/main/res/layout/dialog_drop.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/presentation/src/main/res/layout/item_memory.xml b/presentation/src/main/res/layout/item_memory.xml index a50e2bd..ca7db4e 100644 --- a/presentation/src/main/res/layout/item_memory.xml +++ b/presentation/src/main/res/layout/item_memory.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools"> + @@ -66,6 +67,7 @@ android:id="@+id/llMemoryEdit" android:layout_width="wrap_content" android:layout_height="0dp" + android:background="?attr/selectableItemBackground" android:gravity="center" android:orientation="horizontal" android:paddingHorizontal="@dimen/spacing_16" @@ -107,10 +109,10 @@ android:layout_marginHorizontal="@dimen/spacing_16" android:text="@{item.content}" android:textColor="@color/black" - app:readMoreTextAppearance="@style/Pretendard.Light.14" - app:readMoreTextColor="@color/gray_medium" + app:readMoreMaxLines="2" app:readMoreText="@string/memory_content_more" - app:readMoreMaxLines="2" /> + app:readMoreTextAppearance="@style/Pretendard.Light.14" + app:readMoreTextColor="@color/gray_medium" /> \ No newline at end of file diff --git a/presentation/src/main/res/layout/item_photo.xml b/presentation/src/main/res/layout/item_photo.xml index 4cac629..605e2f9 100644 --- a/presentation/src/main/res/layout/item_photo.xml +++ b/presentation/src/main/res/layout/item_photo.xml @@ -21,8 +21,8 @@ app:imageFile="@{item.file}" /> diff --git a/presentation/src/main/res/values/dimens.xml b/presentation/src/main/res/values/dimens.xml index 675766e..dd6266e 100644 --- a/presentation/src/main/res/values/dimens.xml +++ b/presentation/src/main/res/values/dimens.xml @@ -46,12 +46,17 @@ 5dp 44dp + 36dp + 2dp 4dp 5dp - 36dp + + + 32dp + 5dp \ No newline at end of file diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml index 6eddabc..7aff939 100644 --- a/presentation/src/main/res/values/strings.xml +++ b/presentation/src/main/res/values/strings.xml @@ -48,4 +48,9 @@ 필요한 권한을 허용해주세요. 권한이 거절되었습니다! + + 기록된 추억을 삭제하시겠습니까? + 취소 + 삭제 + \ No newline at end of file