Merge pull request #1431 from Andries-Smit/feat/quickwizard-option-menu

Feature: quick wizard option menu
This commit is contained in:
Milos Kozak 2022-03-11 18:34:49 +01:00 committed by GitHub
commit c17f559d69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 217 additions and 126 deletions

View file

@ -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<QuickWizardEntry> = 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<RecyclerViewAdapter.QuickWizardEntryViewHolder>() {
@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())
}
}

View file

@ -1,25 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".plugins.general.overview.activities.QuickWizardListActivity">
<com.google.android.material.button.MaterialButton
android:id="@+id/add_button"
style="@style/GrayButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/overview_editquickwizardlistactivity_add" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="wrap_content" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:clickable="true"
android:contentDescription="@string/addnew"
android:focusable="true"
android:src="@drawable/ic_add_black_24dp"
tools:ignore="RelativeOverlap" />
</RelativeLayout>

View file

@ -2,7 +2,7 @@
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/overview_quickwizard_cardview"
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
@ -47,7 +47,7 @@
android:orientation="horizontal">
<TextView
android:id="@+id/overview_quickwizard_item_buttonText"
android:id="@+id/buttonText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
@ -58,7 +58,7 @@
tools:ignore="HardcodedText,RtlSymmetry" />
<TextView
android:id="@+id/overview_quickwizard_item_carbs"
android:id="@+id/carbs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="10dp"
@ -71,12 +71,11 @@
</LinearLayout>
<ImageView
android:id="@+id/overview_quickwizard_item_device"
android:id="@+id/device"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="false"
android:cropToPadding="false"
android:paddingEnd="10dp"
android:scaleType="fitStart"
card_view:srcCompat="@drawable/ic_smartphone"
tools:ignore="RtlSymmetry" />
@ -90,6 +89,13 @@
android:scaleType="fitStart"
card_view:srcCompat="@drawable/ic_reorder_gray_24dp" />
<CheckBox
android:id="@+id/cb_remove"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:contentDescription="@string/select_for_removal"
android:minWidth="0dp"/>
</LinearLayout>
<LinearLayout
@ -107,7 +113,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="@+id/overview_quickwizard_item_from"
android:id="@+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
@ -124,7 +130,7 @@
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/overview_quickwizard_item_to"
android:id="@+id/to"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
@ -136,33 +142,11 @@
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
style="@style/GrayButton"
android:id="@+id/overview_quickwizard_item_edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/overview_quickwizard_item_edit_button" />
<com.google.android.material.button.MaterialButton
style="@style/GrayButton"
android:id="@+id/overview_quickwizard_item_remove_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/remove_button" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View file

@ -0,0 +1,14 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/nav_remove_items"
android:title="@string/remove_items"
app:showAsAction="never" />
<item
android:id="@+id/nav_sort_items"
android:title="@string/sort_items"
app:showAsAction="never" />
</menu>

View file

@ -827,6 +827,7 @@
<string name="show_invalidated">Show invalidated</string>
<string name="hide_invalidated">Hide invalidated</string>
<string name="remove_items">Remove items</string>
<string name="sort_items">Sort items</string>
<string name="storedsettingsfound">Stored settings found</string>
<string name="allow_hardware_pump_text">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.</string>
<string name="error_adding_treatment_title">Treatment data incomplete</string>
@ -1222,4 +1223,5 @@
<string name="hide_loop">Hide loop</string>
<string name="show_loop">Show loop</string>
<string name="count_selected">%1$d selected</string>
<string name="sort_label">Sort</string>
</resources>

View file

@ -28,6 +28,8 @@
<item name="notificationLow">@color/notificationLow</item>
<item name="notificationInfo">@color/notificationInfo</item>
<item name="notificationAnnouncement">@color/notificationAnnouncement</item>
<item name="actionModeCloseDrawable">@drawable/ic_close</item>
</style>
<style name="AppTheme.NoActionBar" parent="Theme.MaterialComponents.NoActionBar">