From 01e24ff6a425909555b322f8524958c9bf61fb69 Mon Sep 17 00:00:00 2001 From: Douile <25043847+Douile@users.noreply.github.com> Date: Tue, 16 Aug 2022 11:46:57 +0100 Subject: [PATCH] Add position via dragging the recyclerview --- .../database/QuickChatActionRepository.kt | 4 +-- .../mesh/database/dao/QuickChatActionDao.kt | 22 +-------------- .../mesh/database/entity/QuickChatAction.kt | 2 +- .../java/com/geeksville/mesh/model/UIState.kt | 7 +++-- .../geeksville/mesh/ui/DragManageAdapter.kt | 15 ++++++++-- .../mesh/ui/QuickChatActionAdapter.kt | 17 +++++------ .../mesh/ui/QuickChatSettingsFragment.kt | 28 +++++++++++-------- 7 files changed, 46 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/database/QuickChatActionRepository.kt b/app/src/main/java/com/geeksville/mesh/database/QuickChatActionRepository.kt index 0dcb7106c..0bef1c756 100644 --- a/app/src/main/java/com/geeksville/mesh/database/QuickChatActionRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/database/QuickChatActionRepository.kt @@ -32,7 +32,7 @@ class QuickChatActionRepository @Inject constructor(private val quickChatDaoLazy quickChatActionDao.update(action) } - suspend fun moveAction(action: QuickChatAction, newPos: Int) = withContext(Dispatchers.IO) { - quickChatActionDao.moveAction(action, newPos) + suspend fun setItemPosition(uuid: Long, newPos: Int) = withContext(Dispatchers.IO) { + quickChatActionDao.updateActionPosition(uuid, newPos) } } \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/database/dao/QuickChatActionDao.kt b/app/src/main/java/com/geeksville/mesh/database/dao/QuickChatActionDao.kt index ef3f97107..8af931323 100644 --- a/app/src/main/java/com/geeksville/mesh/database/dao/QuickChatActionDao.kt +++ b/app/src/main/java/com/geeksville/mesh/database/dao/QuickChatActionDao.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow @Dao interface QuickChatActionDao { - @Query("Select * from quick_chat") + @Query("Select * from quick_chat order by position asc") fun getAll(): Flow> @Insert @@ -31,27 +31,7 @@ interface QuickChatActionDao { @Query("Update quick_chat set position=:position WHERE uuid=:uuid") fun updateActionPosition(uuid: Long, position: Int) - @Query("Update quick_chat set position=position+1 where position>=:startInclusive and position<:endExclusive") - fun incrementPositionsBetween(startInclusive: Int, endExclusive: Int) - - @Query("Update quick_chat SET position=position-1 where position>:startExclusive and position<=:endInclusive") - fun decrementPositionsBetween(startExclusive: Int, endInclusive: Int) - @Query("Update quick_chat set position=position-1 where position>=:position") fun decrementPositionsAfter(position: Int) - @Transaction - fun moveAction(action: QuickChatAction, newPos: Int) { - // FIXME: Check newPos is valid - if (newPos < action.position) { - incrementPositionsBetween(newPos, action.position) - updateActionPosition(action.uuid, newPos) - } else if (newPos > action.position) { - decrementPositionsBetween(action.position, newPos) - updateActionPosition(action.uuid, newPos) - } else { - // Do nothing: moving to same position - } - } - } \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/database/entity/QuickChatAction.kt b/app/src/main/java/com/geeksville/mesh/database/entity/QuickChatAction.kt index deeb2d45c..f9cc237f6 100644 --- a/app/src/main/java/com/geeksville/mesh/database/entity/QuickChatAction.kt +++ b/app/src/main/java/com/geeksville/mesh/database/entity/QuickChatAction.kt @@ -5,7 +5,7 @@ import androidx.room.Entity import androidx.room.Index import androidx.room.PrimaryKey -@Entity(tableName = "quick_chat", indices = [Index(value=["position"], unique=true)]) +@Entity(tableName = "quick_chat") data class QuickChatAction( @PrimaryKey(autoGenerate = true) val uuid: Long, @ColumnInfo(name="name") val name: String, diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index df9476d5b..e60170e11 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -21,6 +21,7 @@ import com.geeksville.mesh.repository.datastore.LocalConfigRepository import com.geeksville.mesh.service.MeshService import com.geeksville.mesh.util.positionToMeter import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -490,9 +491,11 @@ class UIViewModel @Inject constructor( } } - fun moveQuickChatAction(action: QuickChatAction, newPos: Int) { + fun updateActionPositions(actions: List) { viewModelScope.launch(Dispatchers.Main) { - quickChatActionRepository.moveAction(action, newPos) + for (position in 0..actions.size) { + quickChatActionRepository.setItemPosition(actions[position].uuid, position) + } } } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/DragManageAdapter.kt b/app/src/main/java/com/geeksville/mesh/ui/DragManageAdapter.kt index 1d24a9e9e..913fa8a51 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/DragManageAdapter.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/DragManageAdapter.kt @@ -1,12 +1,13 @@ package com.geeksville.mesh.ui -import android.content.Context import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView -class DragManageAdapter(var adapter: SwapAdapter, context: Context, dragDirs: Int, swipeDirs: Int) : ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs) { +class DragManageAdapter(var adapter: SwapAdapter, dragDirs: Int, swipeDirs: Int) : + ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs) { interface SwapAdapter { fun swapItems(fromPosition: Int, toPosition: Int) + fun commitSwaps() } override fun onMove( @@ -15,7 +16,15 @@ class DragManageAdapter(var adapter: SwapAdapter, context: Context, dragDirs: In target: RecyclerView.ViewHolder ): Boolean { adapter.swapItems(viewHolder.absoluteAdapterPosition, target.absoluteAdapterPosition) - TODO("Not yet implemented") + return true + } + + override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { + super.onSelectedChanged(viewHolder, actionState) + + if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) { + adapter.commitSwaps() + } } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { diff --git a/app/src/main/java/com/geeksville/mesh/ui/QuickChatActionAdapter.kt b/app/src/main/java/com/geeksville/mesh/ui/QuickChatActionAdapter.kt index 070a723e1..d4563aceb 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/QuickChatActionAdapter.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/QuickChatActionAdapter.kt @@ -1,7 +1,6 @@ package com.geeksville.mesh.ui import android.content.Context -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -12,12 +11,13 @@ import com.geeksville.mesh.database.entity.QuickChatAction class QuickChatActionAdapter internal constructor( context: Context, - private val onEdit: (action: QuickChatAction) -> Unit + private val onEdit: (action: QuickChatAction) -> Unit, + private val repositionAction: (fromPos: Int, toPos: Int) -> Unit, + private val commitAction: () -> Unit, ) : RecyclerView.Adapter(), DragManageAdapter.SwapAdapter { private val inflater: LayoutInflater = LayoutInflater.from(context) private var actions = emptyList() - private val TAG = "QuickChatAdapter" inner class ActionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val actionName: TextView = itemView.findViewById(R.id.quickChatActionName) @@ -27,7 +27,6 @@ class QuickChatActionAdapter internal constructor( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ActionViewHolder { val itemView = inflater.inflate(R.layout.adapter_quick_chat_action_layout, parent, false) - Log.d(TAG, "Created view holder") return ActionViewHolder(itemView) } @@ -35,24 +34,26 @@ class QuickChatActionAdapter internal constructor( val current = actions[position] holder.actionName.text = current.name holder.actionValue.text = current.message - holder.actionEdit.setOnClickListener{ + holder.actionEdit.setOnClickListener { onEdit(current) } - Log.d(TAG, "Bound actions") } internal fun setActions(actions: List) { this.actions = actions notifyDataSetChanged() - Log.d(TAG, String.format("setActions(size=%d, count=%d)", actions.size, itemCount)) } override fun getItemCount() = actions.size override fun swapItems(fromPosition: Int, toPosition: Int) { - // TODO: Update data + repositionAction(fromPosition, toPosition) notifyItemMoved(fromPosition, toPosition) } + override fun commitSwaps() { + commitAction() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/ui/QuickChatSettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/QuickChatSettingsFragment.kt index f0f952f2f..03ddda23e 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/QuickChatSettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/QuickChatSettingsFragment.kt @@ -13,12 +13,13 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import com.geeksville.android.Logging import com.geeksville.mesh.R -import com.geeksville.mesh.databinding.QuickChatSettingsFragmentBinding import com.geeksville.mesh.database.entity.QuickChatAction +import com.geeksville.mesh.databinding.QuickChatSettingsFragmentBinding import com.geeksville.mesh.model.UIViewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.switchmaterial.SwitchMaterial import dagger.hilt.android.AndroidEntryPoint +import java.util.* @AndroidEntryPoint class QuickChatSettingsFragment : ScreenFragment("Quick Chat settings"), Logging { @@ -28,6 +29,8 @@ class QuickChatSettingsFragment : ScreenFragment("Quick Chat settings"), Logging private val model: UIViewModel by activityViewModels() + private lateinit var actions: List + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -39,11 +42,7 @@ class QuickChatSettingsFragment : ScreenFragment("Quick Chat settings"), Logging override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - Log.d(TAG, "viewCreated") - binding.quickChatSettingsCreateButton.setOnClickListener { - Log.d(TAG, "Create quick chat") - val builder = createEditDialog(requireContext(), "New quick chat") builder.builder.setPositiveButton("Add") { view, x -> @@ -62,7 +61,7 @@ class QuickChatSettingsFragment : ScreenFragment("Quick Chat settings"), Logging } val quickChatActionAdapter = - QuickChatActionAdapter(requireContext()) { action: QuickChatAction -> + QuickChatActionAdapter(requireContext(), { action: QuickChatAction -> val builder = createEditDialog(requireContext(), "Edit quick chat") builder.nameInput.setText(action.name) builder.messageInput.setText(action.message) @@ -83,9 +82,14 @@ class QuickChatSettingsFragment : ScreenFragment("Quick Chat settings"), Logging } val dialog = builder.builder.create() dialog.show() - } + }, { fromPos, toPos -> + Collections.swap(actions, fromPos, toPos) + }, { + model.updateActionPositions(actions) + }) - val dragCallback = DragManageAdapter(quickChatActionAdapter, requireContext(), ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) + val dragCallback = + DragManageAdapter(quickChatActionAdapter, ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) val helper = ItemTouchHelper(dragCallback) binding.quickChatSettingsView.apply { @@ -94,12 +98,12 @@ class QuickChatSettingsFragment : ScreenFragment("Quick Chat settings"), Logging helper.attachToRecyclerView(this) } - model.quickChatActions.asLiveData().observe(viewLifecycleOwner) { actions -> - actions?.let { quickChatActionAdapter.setActions(actions) } + actions?.let { + quickChatActionAdapter.setActions(actions) + this.actions = actions + } } - - Log.d(TAG, "viewCreation done") } data class DialogBuilder(