From 24ee3fc7c96b0bfa4f838bcc004554d61968eb84 Mon Sep 17 00:00:00 2001 From: Andries Smit Date: Thu, 10 Mar 2022 22:15:24 +0100 Subject: [PATCH 1/8] Feat: quickwizard action menu --- .../activities/QuickWizardListActivity.kt | 245 ++++++++++++------ .../overview_quickwizardlist_activity.xml | 36 +-- .../layout/overview_quickwizardlist_item.xml | 44 +--- app/src/main/res/menu/menu_quickwizard.xml | 14 + app/src/main/res/values/strings.xml | 2 + core/src/main/res/values/styles.xml | 2 + 6 files changed, 217 insertions(+), 126 deletions(-) create mode 100644 app/src/main/res/menu/menu_quickwizard.xml diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt index c3e3fd1b9f..c19899c75a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/activities/QuickWizardListActivity.kt @@ -2,15 +2,9 @@ package info.nightscout.androidaps.plugins.general.overview.activities import android.annotation.SuppressLint import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.MenuItem -import android.view.MotionEvent -import android.view.View -import android.view.ViewGroup -import android.widget.Button -import android.widget.ImageView -import android.widget.TextView +import android.util.SparseArray +import android.view.* +import androidx.core.util.forEach import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_DRAG @@ -23,11 +17,14 @@ import androidx.recyclerview.widget.RecyclerView import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.DaggerAppCompatActivityWithResult import info.nightscout.androidaps.databinding.OverviewQuickwizardlistActivityBinding +import info.nightscout.androidaps.databinding.OverviewQuickwizardlistItemBinding +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.wizard.QuickWizard import info.nightscout.androidaps.utils.wizard.QuickWizardEntry @@ -46,17 +43,16 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() { @Inject lateinit var sp: SP private var disposable: CompositeDisposable = CompositeDisposable() + private var selectedItems: SparseArray = SparseArray() + private var removeActionMode: ActionMode? = null + private var sortActionMode: ActionMode? = null private lateinit var binding: OverviewQuickwizardlistActivityBinding private val itemTouchHelper by lazy { val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback(UP or DOWN or START or END, 0) { - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { val adapter = recyclerView.adapter as RecyclerViewAdapter val from = viewHolder.layoutPosition val to = target.layoutPosition @@ -66,12 +62,10 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() { return true } - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - } + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {} override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) { super.onSelectedChanged(viewHolder, actionState) - if (actionState == ACTION_STATE_DRAG) { viewHolder?.itemView?.alpha = 0.5f } @@ -79,11 +73,8 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() { override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { super.clearView(recyclerView, viewHolder) - viewHolder.itemView.alpha = 1.0f - - val adapter = recyclerView.adapter as RecyclerViewAdapter - adapter.onDrop() + (recyclerView.adapter as RecyclerViewAdapter).onDrop() } } @@ -96,82 +87,84 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() { private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter() { - @SuppressLint("ClickableViewAccessibility") + private inner class QuickWizardEntryViewHolder(val binding: OverviewQuickwizardlistItemBinding, val fragmentManager: FragmentManager) : RecyclerView.ViewHolder(binding.root) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickWizardEntryViewHolder { - val itemView = LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false) - val viewHolder = QuickWizardEntryViewHolder(itemView, fragmentManager) - - viewHolder.handleView.setOnTouchListener { _, event -> - if (event.actionMasked == MotionEvent.ACTION_DOWN) { - startDragging(viewHolder) - } - return@setOnTouchListener true - } - - return viewHolder + val binding = OverviewQuickwizardlistItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return QuickWizardEntryViewHolder(binding, fragmentManager) } + @SuppressLint("ClickableViewAccessibility") override fun onBindViewHolder(holder: QuickWizardEntryViewHolder, position: Int) { - holder.from.text = dateUtil.timeString(quickWizard[position].validFromDate()) - holder.to.text = dateUtil.timeString(quickWizard[position].validToDate()) - val wearControl = sp.getBoolean(R.string.key_wear_control, false) - - if (wearControl) { - holder.handleView.visibility = View.VISIBLE + val entry = quickWizard[position] + holder.binding.from.text = dateUtil.timeString(entry.validFromDate()) + holder.binding.to.text = dateUtil.timeString(entry.validToDate()) + holder.binding.buttonText.text = entry.buttonText() + holder.binding.carbs.text = rh.gs(R.string.format_carbs, entry.carbs()) + if (entry.device() == QuickWizardEntry.DEVICE_ALL) { + holder.binding.device.visibility = View.GONE } else { - holder.handleView.visibility = View.GONE - } - if (quickWizard[position].device() == QuickWizardEntry.DEVICE_ALL) { - holder.device.visibility = View.GONE - } else { - holder.device.visibility = View.VISIBLE - holder.device.setImageResource( + holder.binding.device.visibility = View.VISIBLE + holder.binding.device.setImageResource( when (quickWizard[position].device()) { QuickWizardEntry.DEVICE_WATCH -> R.drawable.ic_watch else -> R.drawable.ic_smartphone } ) } - holder.buttonText.text = quickWizard[position].buttonText() - holder.carbs.text = rh.gs(R.string.format_carbs, quickWizard[position].carbs()) + + if (sortActionMode != null && removeActionMode != null) { + holder.binding.cardview.setOnClickListener { + val manager = fragmentManager + val editQuickWizardDialog = EditQuickWizardDialog() + val bundle = Bundle() + bundle.putInt("position", position) + editQuickWizardDialog.arguments = bundle + editQuickWizardDialog.show(manager, "EditQuickWizardDialog") + } + } + + fun updateSelection(selected: Boolean) { + if (selected) { + selectedItems.put(position, entry) + } else { + selectedItems.remove(position) + } + removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size()) + } + + holder.binding.cardview.setOnTouchListener { _, event -> + if (event.actionMasked == MotionEvent.ACTION_UP && sortActionMode == null && removeActionMode == null) { + val manager = fragmentManager + val editQuickWizardDialog = EditQuickWizardDialog() + val bundle = Bundle() + bundle.putInt("position", position) + editQuickWizardDialog.arguments = bundle + editQuickWizardDialog.show(manager, "EditQuickWizardDialog") + } + if (event.actionMasked == MotionEvent.ACTION_DOWN && sortActionMode != null) { + startDragging(holder) + } + if (event.actionMasked == MotionEvent.ACTION_UP && removeActionMode != null) { + holder.binding.cbRemove.toggle() + updateSelection(holder.binding.cbRemove.isChecked) + } + return@setOnTouchListener true + } + holder.binding.cbRemove.isChecked = selectedItems.get(position) != null + holder.binding.cbRemove.setOnCheckedChangeListener { _, value -> updateSelection(value) } + holder.binding.handleView.visibility = (sortActionMode != null).toVisibility() + holder.binding.cbRemove.visibility = (removeActionMode != null).toVisibility() + removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size()) } override fun getItemCount(): Int = quickWizard.size() - private inner class QuickWizardEntryViewHolder(itemView: View, var fragmentManager: FragmentManager) : RecyclerView.ViewHolder(itemView) { - - val buttonText: TextView = itemView.findViewById(R.id.overview_quickwizard_item_buttonText) - val carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs) - val from: TextView = itemView.findViewById(R.id.overview_quickwizard_item_from) - val handleView: ImageView = itemView.findViewById(R.id.handleView) - val device: ImageView = itemView.findViewById(R.id.overview_quickwizard_item_device) - val to: TextView = itemView.findViewById(R.id.overview_quickwizard_item_to) - private val editButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_edit_button) - private val removeButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_remove_button) - - init { - editButton.setOnClickListener { - val manager = fragmentManager - val editQuickWizardDialog = EditQuickWizardDialog() - val bundle = Bundle() - bundle.putInt("position", bindingAdapterPosition) - editQuickWizardDialog.arguments = bundle - editQuickWizardDialog.show(manager, "EditQuickWizardDialog") - } - removeButton.setOnClickListener { - quickWizard.remove(bindingAdapterPosition) - rxBus.send(EventQuickWizardChange()) - } - } - } - fun moveItem(from: Int, to: Int) { - Log.i("QuickWizard", "moveItem") quickWizard.move(from, to) } fun onDrop() { - Log.i("QuickWizard", "onDrop") rxBus.send(EventQuickWizardChange()) } } @@ -213,13 +206,107 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() { super.onPause() } + private fun removeSelected() { + if (selectedItems.size() > 0) + OKDialog.showConfirmation(this, rh.gs(R.string.removerecord), getConfirmationText(), Runnable { + selectedItems.forEach { _, item -> + quickWizard.remove(item.position) + rxBus.send(EventQuickWizardChange()) + } + removeActionMode?.finish() + }) + else + removeActionMode?.finish() + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + val inflater = menuInflater + inflater.inflate(R.menu.menu_quickwizard, menu) + return super.onCreateOptionsMenu(menu) + } + override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { - android.R.id.home -> { + android.R.id.home -> { finish() true } - else -> false + R.id.nav_remove_items -> { + removeActionMode = startActionMode(RemoveActionModeCallback()) + true + } + + R.id.nav_sort_items -> { + sortActionMode = startActionMode(SortActionModeCallback()) + true + } + + else -> false } + + inner class RemoveActionModeCallback : ActionMode.Callback { + + override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean { + mode.menuInflater.inflate(R.menu.menu_delete_selection, menu) + selectedItems.clear() + mode.title = rh.gs(R.string.count_selected, selectedItems.size()) + binding.recyclerview.adapter?.notifyDataSetChanged() + return true + } + + override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false + + override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { + return when (item.itemId) { + R.id.remove_selected -> { + removeSelected() + true + } + + else -> false + } + } + + override fun onDestroyActionMode(mode: ActionMode?) { + removeActionMode = null + binding.recyclerview.adapter?.notifyDataSetChanged() + } + } + + inner class SortActionModeCallback : ActionMode.Callback { + + override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean { + mode.title = rh.gs(R.string.sort_label) + binding.recyclerview.adapter?.notifyDataSetChanged() + return true + } + + override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false + + override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { + return when (item.itemId) { + R.id.remove_selected -> { + removeSelected() + true + } + + else -> false + } + } + + override fun onDestroyActionMode(mode: ActionMode?) { + sortActionMode = null + binding.recyclerview.adapter?.notifyDataSetChanged() + } + } + + private fun getConfirmationText(): String { + if (selectedItems.size() == 1) { + val entry = selectedItems.valueAt(0) + return "${rh.gs(R.string.remove_button)} ${entry.buttonText()} ${rh.gs(R.string.format_carbs, entry.carbs())}\n" + + "${dateUtil.timeString(entry.validFromDate())} - ${dateUtil.timeString(entry.validToDate())}" + } + return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size()) + } } diff --git a/app/src/main/res/layout/overview_quickwizardlist_activity.xml b/app/src/main/res/layout/overview_quickwizardlist_activity.xml index a95c6d9516..31139e0bca 100644 --- a/app/src/main/res/layout/overview_quickwizardlist_activity.xml +++ b/app/src/main/res/layout/overview_quickwizardlist_activity.xml @@ -1,25 +1,27 @@ - - - + android:layout_height="wrap_content" /> - + + + diff --git a/app/src/main/res/layout/overview_quickwizardlist_item.xml b/app/src/main/res/layout/overview_quickwizardlist_item.xml index 5cf0f538d1..dc729b4109 100644 --- a/app/src/main/res/layout/overview_quickwizardlist_item.xml +++ b/app/src/main/res/layout/overview_quickwizardlist_item.xml @@ -2,7 +2,7 @@ @@ -90,6 +89,13 @@ android:scaleType="fitStart" card_view:srcCompat="@drawable/ic_reorder_gray_24dp" /> + + + - - - - - - - - diff --git a/app/src/main/res/menu/menu_quickwizard.xml b/app/src/main/res/menu/menu_quickwizard.xml new file mode 100644 index 0000000000..7a3e86905d --- /dev/null +++ b/app/src/main/res/menu/menu_quickwizard.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 07bf55f635..d35da6ce93 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -827,6 +827,7 @@ Show invalidated Hide invalidated Remove items + Sort items Stored settings found Attention: If you activate and connect to a hardware pump, AndroidAPS will copy the basal settings from the profile to the pump, overwriting the existing basal rate stored on the pump. Make sure you have the correct basal setting in AndroidAPS. If you are not sure or don\'t want to overwrite the basal settings on your pump, press cancel and repeat switching to the pump at a later time. Treatment data incomplete @@ -1222,4 +1223,5 @@ Hide loop Show loop %1$d selected + Sort diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index b22248a881..0d5083feef 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -28,6 +28,8 @@ @color/notificationLow @color/notificationInfo @color/notificationAnnouncement + + @drawable/ic_close