From 18a51e0f8ccc2cc326eeeac08dfdcd9ca7f9f649 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Fri, 1 Nov 2024 18:55:46 +0900 Subject: [PATCH 1/3] [feat] #180 clip drag and drop --- .../org/sopt/clip/clipedit/ClipEditAdapter.kt | 36 ++++------ .../sopt/clip/clipedit/ClipEditFragment.kt | 68 ++++++++++--------- .../sopt/clip/clipedit/ClipEditViewHolder.kt | 5 -- .../sopt/clip/clipedit/ClipEditViewModel.kt | 8 +-- .../sopt/clip/clipedit/ItemTouchCallback.kt | 57 +++++++++++++--- .../main/res/layout/fragment_clip_edit.xml | 10 +++ 6 files changed, 109 insertions(+), 75 deletions(-) diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt index 0afe2201..7630b9c8 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt @@ -9,15 +9,11 @@ import org.sopt.ui.view.ItemDiffCallback class ClipEditAdapter( private val itemClick: (Long, String, Long, String) -> Unit, - private val deleteClip: (Long) -> Unit, - private val onLongClick: (Long) -> Unit, - private val onLongClick2: (Long) -> Unit, -) : ListAdapter(DiffUtil), ItemTouchHelperListener { +) : ListAdapter(DiffUtil) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ClipEditViewHolder { return ClipEditViewHolder( ItemClipEditClipBinding.inflate(LayoutInflater.from(parent.context), parent, false), itemClick, - onLongClick, ) } @@ -25,29 +21,21 @@ class ClipEditAdapter( holder.onBind(getItem(position)) } + fun getList(): List { + return currentList.toList() + } + + fun moveItem(fromPosition: Int, toPosition: Int) { + val currentList = currentList.toMutableList() + val item = currentList.removeAt(fromPosition) + currentList.add(toPosition, item) + submitList(currentList) + } + companion object { private val DiffUtil = ItemDiffCallback( onItemsTheSame = { old, new -> old.categoryId == new.categoryId }, onContentsTheSame = { old, new -> old == new }, ) } - - override fun onItemMove(from: Int, to: Int) { - val item: Category? = currentList[from] - val newList = ArrayList() - newList.addAll(currentList) - newList.removeAt(from) - if (item != null) { - newList.add(to, item) - } - notifyItemMoved(from, to) - onLongClick2(to.toLong()) - } - - override fun onItemSwipe(position: Int) { - val newList = ArrayList(currentList) - deleteClip(newList[position].categoryId ?: 0) - newList.removeAt(position) - notifyItemRemoved(position) - } } diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt index 66591c37..bdf20d67 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt @@ -24,48 +24,38 @@ import org.sopt.ui.view.onThrottleClick class ClipEditFragment : BindingFragment({ FragmentClipEditBinding.inflate(it) }) { private val viewModel: ClipEditViewModel by viewModels() private lateinit var clipEditAdapter: ClipEditAdapter - private val itemTouchHelper by lazy { - ItemTouchHelper(ItemTouchCallback(clipEditAdapter)) - } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - clipEditAdapter = ClipEditAdapter( - { itemId, state, position, title -> - when (state) { - "delete" -> { - showDeleteDialog(itemId, title) - } + clipEditAdapter = ClipEditAdapter { itemId, state, position, title -> + when (state) { + "delete" -> { + showDeleteDialog(itemId, title) + } - "edit" -> { - showHomeBottomSheet(itemId, title) - } + "edit" -> { + showHomeBottomSheet(itemId, title) } - }, - deleteClip = { - viewModel.deleteCategory(it) - }, - onLongClick = { - viewModel.last2.flowWithLifecycle(viewLifeCycle).onEach { state -> - when (state) { - is UiState.Success -> { - viewModel.patchCategoryEditPriority(it, state.data + 1) - } - - else -> {} - } - }.launchIn(viewLifeCycleScope) - }, - onLongClick2 = { - viewModel.update2(it.toInt()) - }, - ) + } + } binding.rvClipEdit.adapter = clipEditAdapter - itemTouchHelper.attachToRecyclerView(binding.rvClipEdit) + val callback = ItemTouchCallback( + adapter = clipEditAdapter, + recyclerView = binding.rvClipEdit, + ) { newIndexList -> + newIndexList.forEachIndexed { index, value -> + value.categoryId?.let { + viewModel.update2(it, index) + } + } + } + ItemTouchHelper(callback).attachToRecyclerView(binding.rvClipEdit) + updateEditListView() updateDelete() onClickBackButton() + editCategoryPriority() } private fun updateEditListView() { @@ -117,7 +107,7 @@ class ClipEditFragment : BindingFragment({ FragmentClip } } - fun editCategoryTitle() { + private fun editCategoryTitle() { viewModel.editTitleState.flowWithLifecycle(viewLifeCycle).onEach { state -> when (state) { is UiState.Success -> { @@ -144,4 +134,16 @@ class ClipEditFragment : BindingFragment({ FragmentClip } .show() } + + private fun editCategoryPriority() { + viewModel.last2.flowWithLifecycle(viewLifeCycle).onEach { state -> + when (state) { + is UiState.Success -> { + viewModel.patchCategoryEditPriority(state.data.first, state.data.second) + } + + else -> {} + } + }.launchIn(viewLifeCycleScope) + } } diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewHolder.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewHolder.kt index bfbbbd8d..795ab55a 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewHolder.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewHolder.kt @@ -8,7 +8,6 @@ import org.sopt.model.category.Category class ClipEditViewHolder( private val binding: ItemClipEditClipBinding, private val onClickItemClip: (Long, String, Long, String) -> Unit, - private val onLongClick: (Long) -> Unit, ) : RecyclerView.ViewHolder(binding.root) { fun onBind(clipData: Category) { if (clipData == null) return @@ -29,10 +28,6 @@ class ClipEditViewHolder( onClickItemClip(clipData.categoryId!!.toLong(), "delete", itemId, clipData.categoryTitle ?: "") } } - root.setOnLongClickListener { - onLongClick(clipData.categoryId!!.toLong()) - true - } } } } diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt index b1f9c980..ae709eb2 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt @@ -32,11 +32,11 @@ class ClipEditViewModel @Inject constructor( private val _editTitleState = MutableStateFlow>(UiState.Empty) val editTitleState: StateFlow> = _editTitleState.asStateFlow() - private val _last2 = MutableStateFlow>(UiState.Empty) - val last2: StateFlow> = _last2.asStateFlow() + private val _last2 = MutableStateFlow>>(UiState.Empty) + val last2: StateFlow>> = _last2.asStateFlow() - fun update2(a: Int) = viewModelScope.launch { - _last2.emit(UiState.Success(a)) + fun update2(clipId: Long, newIndex:Int) = viewModelScope.launch { + _last2.emit(UiState.Success(Pair(clipId,newIndex))) } init { diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt index 109cf5a0..f3b635f8 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt @@ -1,22 +1,61 @@ package org.sopt.clip.clipedit +import android.util.Log +import android.view.View +import androidx.core.view.children import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView +import org.sopt.clip.R +import org.sopt.model.category.Category -class ItemTouchCallback(private val listener: ItemTouchHelperListener) : ItemTouchHelper.Callback() { +class ItemTouchCallback( + private val adapter: ClipEditAdapter, + private val recyclerView: RecyclerView, + private val onClearView: (List) -> Unit, +) : ItemTouchHelper.Callback() { - override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { - val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN - val swipeFlags = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT - return makeMovementFlags(dragFlags, swipeFlags) + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + ): Int { + val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.START or ItemTouchHelper.END + return makeMovementFlags(dragFlags, 0) } - override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { - listener.onItemMove(viewHolder.adapterPosition, target.adapterPosition) - return false + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder, + ): Boolean { + val fromPosition = viewHolder.bindingAdapterPosition + val toPosition = target.bindingAdapterPosition + adapter.moveItem(fromPosition, toPosition) + return true } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - listener.onItemSwipe(viewHolder.layoutPosition) + } + + override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { + super.clearView(recyclerView, viewHolder) + + val finalList = adapter.getList() + val fifinalList: MutableList = mutableListOf() + finalList.withIndex().forEach { + fifinalList.add(Category(categoryId = it.value.categoryId, categoryTitle = it.value.categoryTitle, toastNum = it.value.toastNum)) + } + + Log.e("리스트", fifinalList.toString()) + + onClearView(fifinalList) + + viewHolder.itemView.animate().scaleX(1.0f).scaleY(1.0f).setDuration(200).start() + } + + override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { + super.onSelectedChanged(viewHolder, actionState) + viewHolder?.itemView?.let { + it.animate().scaleX(1.1f).scaleY(1.1f).setDuration(200).start() + } } } diff --git a/feature/clip/src/main/res/layout/fragment_clip_edit.xml b/feature/clip/src/main/res/layout/fragment_clip_edit.xml index f9a90821..e6d6189f 100644 --- a/feature/clip/src/main/res/layout/fragment_clip_edit.xml +++ b/feature/clip/src/main/res/layout/fragment_clip_edit.xml @@ -96,6 +96,15 @@ app:layout_constraintTop_toBottomOf="@id/iv_pin" tools:itemCount="3" tools:listitem="@layout/item_clip_edit_clip" /> + + @@ -104,4 +113,5 @@ android:layout_width="match_parent" android:layout_height="20dp" app:layout_constraintBottom_toBottomOf="parent"/> + From c37588c48708f9b56ffd9cb088e4bc616b303a9f Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Fri, 1 Nov 2024 19:25:32 +0900 Subject: [PATCH 2/3] [refactor] #180 refactor callback --- .../org/sopt/clip/clipedit/ClipEditAdapter.kt | 8 +++---- .../sopt/clip/clipedit/ClipEditFragment.kt | 11 +++------ .../sopt/clip/clipedit/ClipEditViewModel.kt | 12 +++++----- .../sopt/clip/clipedit/ItemTouchCallback.kt | 23 +++---------------- 4 files changed, 16 insertions(+), 38 deletions(-) diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt index 7630b9c8..2e332803 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditAdapter.kt @@ -21,10 +21,6 @@ class ClipEditAdapter( holder.onBind(getItem(position)) } - fun getList(): List { - return currentList.toList() - } - fun moveItem(fromPosition: Int, toPosition: Int) { val currentList = currentList.toMutableList() val item = currentList.removeAt(fromPosition) @@ -32,6 +28,10 @@ class ClipEditAdapter( submitList(currentList) } + fun getCategoryId(position: Int): Long? { + return currentList[position].categoryId + } + companion object { private val DiffUtil = ItemDiffCallback( onItemsTheSame = { old, new -> old.categoryId == new.categoryId }, diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt index bdf20d67..2acab12e 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditFragment.kt @@ -43,15 +43,10 @@ class ClipEditFragment : BindingFragment({ FragmentClip val callback = ItemTouchCallback( adapter = clipEditAdapter, recyclerView = binding.rvClipEdit, - ) { newIndexList -> - newIndexList.forEachIndexed { index, value -> - value.categoryId?.let { - viewModel.update2(it, index) - } - } + ) { categoryId, newIndex -> + if (categoryId != null) viewModel.updateCategoryEditPriorityState(categoryId, newIndex) } ItemTouchHelper(callback).attachToRecyclerView(binding.rvClipEdit) - updateEditListView() updateDelete() onClickBackButton() @@ -136,7 +131,7 @@ class ClipEditFragment : BindingFragment({ FragmentClip } private fun editCategoryPriority() { - viewModel.last2.flowWithLifecycle(viewLifeCycle).onEach { state -> + viewModel.categoryEditPriorityState.flowWithLifecycle(viewLifeCycle).onEach { state -> when (state) { is UiState.Success -> { viewModel.patchCategoryEditPriority(state.data.first, state.data.second) diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt index ae709eb2..df48f103 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt @@ -32,17 +32,17 @@ class ClipEditViewModel @Inject constructor( private val _editTitleState = MutableStateFlow>(UiState.Empty) val editTitleState: StateFlow> = _editTitleState.asStateFlow() - private val _last2 = MutableStateFlow>>(UiState.Empty) - val last2: StateFlow>> = _last2.asStateFlow() - - fun update2(clipId: Long, newIndex:Int) = viewModelScope.launch { - _last2.emit(UiState.Success(Pair(clipId,newIndex))) - } + private val _categoryEditPriorityState = MutableStateFlow>>(UiState.Empty) + val categoryEditPriorityState: StateFlow>> = _categoryEditPriorityState.asStateFlow() init { getCategoryAll() } + fun updateCategoryEditPriorityState(clipId: Long, newIndex: Int) = viewModelScope.launch { + _categoryEditPriorityState.emit(UiState.Success(Pair(clipId, newIndex))) + } + fun getCategoryAll() = viewModelScope.launch { getCategoryAll.invoke().onSuccess { val allCategoryList = listOf( diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt index f3b635f8..b8958bac 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchCallback.kt @@ -1,17 +1,12 @@ package org.sopt.clip.clipedit -import android.util.Log -import android.view.View -import androidx.core.view.children import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -import org.sopt.clip.R -import org.sopt.model.category.Category class ItemTouchCallback( private val adapter: ClipEditAdapter, private val recyclerView: RecyclerView, - private val onClearView: (List) -> Unit, + private val onMoveItem: (Long?, Int) -> Unit, ) : ItemTouchHelper.Callback() { override fun getMovementFlags( @@ -38,24 +33,12 @@ class ItemTouchCallback( override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { super.clearView(recyclerView, viewHolder) - - val finalList = adapter.getList() - val fifinalList: MutableList = mutableListOf() - finalList.withIndex().forEach { - fifinalList.add(Category(categoryId = it.value.categoryId, categoryTitle = it.value.categoryTitle, toastNum = it.value.toastNum)) - } - - Log.e("리스트", fifinalList.toString()) - - onClearView(fifinalList) - + onMoveItem(adapter.getCategoryId(viewHolder.bindingAdapterPosition), viewHolder.bindingAdapterPosition) viewHolder.itemView.animate().scaleX(1.0f).scaleY(1.0f).setDuration(200).start() } override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { super.onSelectedChanged(viewHolder, actionState) - viewHolder?.itemView?.let { - it.animate().scaleX(1.1f).scaleY(1.1f).setDuration(200).start() - } + viewHolder?.itemView?.animate()?.scaleX(1.1f)?.scaleY(1.1f)?.setDuration(200)?.start() } } From 3b06fb678a26b798370c18985072272bc6ec6d82 Mon Sep 17 00:00:00 2001 From: leeseokchan00 <112953135+leeseokchan00@users.noreply.github.com> Date: Sat, 2 Nov 2024 01:16:45 +0900 Subject: [PATCH 3/3] [chore] #180 ktlint --- .../java/org/sopt/clip/clipedit/ClipEditViewModel.kt | 2 +- .../org/sopt/clip/clipedit/ItemTouchHelperListener.kt | 6 ------ feature/clip/src/main/res/layout/fragment_clip_edit.xml | 9 --------- 3 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchHelperListener.kt diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt index df48f103..89f71a5f 100644 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt +++ b/feature/clip/src/main/java/org/sopt/clip/clipedit/ClipEditViewModel.kt @@ -42,7 +42,7 @@ class ClipEditViewModel @Inject constructor( fun updateCategoryEditPriorityState(clipId: Long, newIndex: Int) = viewModelScope.launch { _categoryEditPriorityState.emit(UiState.Success(Pair(clipId, newIndex))) } - + fun getCategoryAll() = viewModelScope.launch { getCategoryAll.invoke().onSuccess { val allCategoryList = listOf( diff --git a/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchHelperListener.kt b/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchHelperListener.kt deleted file mode 100644 index db79afa3..00000000 --- a/feature/clip/src/main/java/org/sopt/clip/clipedit/ItemTouchHelperListener.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.sopt.clip.clipedit - -interface ItemTouchHelperListener { - fun onItemMove(from: Int, to: Int) - fun onItemSwipe(position: Int) -} diff --git a/feature/clip/src/main/res/layout/fragment_clip_edit.xml b/feature/clip/src/main/res/layout/fragment_clip_edit.xml index e6d6189f..fedb1aba 100644 --- a/feature/clip/src/main/res/layout/fragment_clip_edit.xml +++ b/feature/clip/src/main/res/layout/fragment_clip_edit.xml @@ -96,15 +96,6 @@ app:layout_constraintTop_toBottomOf="@id/iv_pin" tools:itemCount="3" tools:listitem="@layout/item_clip_edit_clip" /> - -