chore: shared action helper sort and remove
This commit is contained in:
parent
0c4cf71ef8
commit
b2bfd47bcb
15 changed files with 436 additions and 443 deletions
|
@ -7,11 +7,6 @@ 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
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.DOWN
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.END
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.START
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.UP
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -20,8 +15,12 @@ import info.nightscout.androidaps.databinding.OverviewQuickwizardlistActivityBin
|
|||
import info.nightscout.androidaps.databinding.OverviewQuickwizardlistItemBinding
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.utils.dragHelpers.ItemTouchHelperAdapter
|
||||
import info.nightscout.androidaps.utils.dragHelpers.OnStartDragListener
|
||||
import info.nightscout.androidaps.utils.dragHelpers.SimpleItemTouchHelperCallback
|
||||
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
|
||||
import info.nightscout.androidaps.utils.ActionHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
|
@ -33,7 +32,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
|||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||
class QuickWizardListActivity : DaggerAppCompatActivityWithResult(), OnStartDragListener {
|
||||
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
|
@ -43,49 +42,15 @@ 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 actionHelper: ActionHelper<QuickWizardEntry>
|
||||
private val itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback())
|
||||
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 {
|
||||
val adapter = recyclerView.adapter as RecyclerViewAdapter
|
||||
val from = viewHolder.layoutPosition
|
||||
val to = target.layoutPosition
|
||||
adapter.moveItem(from, to)
|
||||
adapter.notifyItemMoved(from, to)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
viewHolder.itemView.alpha = 1.0f
|
||||
(recyclerView.adapter as RecyclerViewAdapter).onDrop()
|
||||
}
|
||||
}
|
||||
|
||||
ItemTouchHelper(simpleItemTouchCallback)
|
||||
}
|
||||
|
||||
fun startDragging(viewHolder: RecyclerView.ViewHolder) {
|
||||
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
|
||||
itemTouchHelper.startDrag(viewHolder)
|
||||
}
|
||||
|
||||
private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>() {
|
||||
private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>(), ItemTouchHelperAdapter {
|
||||
|
||||
private inner class QuickWizardEntryViewHolder(val binding: OverviewQuickwizardlistItemBinding, val fragmentManager: FragmentManager) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
|
@ -113,60 +78,48 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
)
|
||||
}
|
||||
|
||||
if (sortActionMode != null && removeActionMode != null) {
|
||||
holder.binding.cardview.setOnClickListener {
|
||||
fun click() {
|
||||
if (actionHelper.isNoAction) {
|
||||
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) {
|
||||
} else if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.toggle()
|
||||
updateSelection(holder.binding.cbRemove.isChecked)
|
||||
actionHelper.updateSelection(position, entry, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
}
|
||||
// For accessibility add click lister too, unfortunately sort can not made accessible
|
||||
holder.binding.root.setOnClickListener {
|
||||
click()
|
||||
}
|
||||
holder.binding.root.setOnTouchListener { _, event ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_UP) {
|
||||
click()
|
||||
} else if (event.actionMasked == MotionEvent.ACTION_DOWN && actionHelper.isSorting) {
|
||||
onStartDrag(holder)
|
||||
}
|
||||
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())
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, entry, value)
|
||||
}
|
||||
holder.binding.handleView.visibility = actionHelper.isSorting.toVisibility()
|
||||
holder.binding.cbRemove.visibility = actionHelper.isRemoving.toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = quickWizard.size()
|
||||
override fun getItemCount() = quickWizard.size()
|
||||
|
||||
fun moveItem(from: Int, to: Int) {
|
||||
quickWizard.move(from, to)
|
||||
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
|
||||
binding.recyclerview.adapter?.notifyItemMoved(fromPosition, toPosition)
|
||||
quickWizard.move(fromPosition, toPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
fun onDrop() {
|
||||
rxBus.send(EventQuickWizardChange())
|
||||
}
|
||||
override fun onDrop() = rxBus.send(EventQuickWizardChange())
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -174,6 +127,11 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
binding = OverviewQuickwizardlistActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
actionHelper = ActionHelper(rh, this)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
actionHelper.enableSort = true
|
||||
|
||||
title = rh.gs(R.string.quickwizard)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
|
@ -184,6 +142,7 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
itemTouchHelper.attachToRecyclerView(binding.recyclerview)
|
||||
|
||||
binding.addButton.setOnClickListener {
|
||||
actionHelper.finish()
|
||||
val manager = supportFragmentManager
|
||||
val editQuickWizardDialog = EditQuickWizardDialog()
|
||||
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
||||
|
@ -203,105 +162,37 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
|
||||
override fun onPause() {
|
||||
disposable.clear()
|
||||
actionHelper.finish()
|
||||
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()
|
||||
private fun removeSelected(selectedItems: SparseArray<QuickWizardEntry>) {
|
||||
OKDialog.showConfirmation(this, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, item ->
|
||||
quickWizard.remove(item.position)
|
||||
rxBus.send(EventQuickWizardChange())
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
val inflater = menuInflater
|
||||
inflater.inflate(R.menu.menu_quickwizard, menu)
|
||||
menuInflater.inflate(R.menu.menu_actions, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
android.R.id.home -> {
|
||||
finish()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
else -> actionHelper.onOptionsItemSelected(item)
|
||||
|
||||
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 {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<QuickWizardEntry>): 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" +
|
||||
|
@ -309,4 +200,5 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
}
|
||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.source
|
|||
import android.os.Bundle
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -26,6 +25,7 @@ import info.nightscout.androidaps.interfaces.PluginBase
|
|||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.utils.ActionHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -54,11 +54,9 @@ class BGSourceFragment : DaggerFragment() {
|
|||
|
||||
private val disposable = CompositeDisposable()
|
||||
private val millsToThePast = T.hours(36).msecs()
|
||||
private var selectedItems: SparseArray<GlucoseValue> = SparseArray()
|
||||
private var toolbar: Toolbar? = null
|
||||
private var removeActionMode: ActionMode? = null
|
||||
|
||||
private lateinit var actionHelper: ActionHelper<GlucoseValue>
|
||||
private var _binding: BgsourceFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
|
@ -67,8 +65,10 @@ class BGSourceFragment : DaggerFragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
toolbar = activity?.findViewById(R.id.toolbar)
|
||||
setHasOptionsMenu(true)
|
||||
actionHelper = ActionHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(actionHelper.inMenu)
|
||||
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
|
@ -97,44 +97,30 @@ class BGSourceFragment : DaggerFragment() {
|
|||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
removeActionMode?.finish()
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.menu_bgsource, menu)
|
||||
actionHelper.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
// Only show when tab bg source is shown
|
||||
menu.findItem(R.id.nav_remove_items)?.isVisible = isResumed
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
actionHelper.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.finish()
|
||||
binding.recyclerview.adapter = null // avoid leaks
|
||||
_binding = null
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
if (toolbar != null) {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback()) // in overview
|
||||
} else {
|
||||
removeActionMode = activity?.startActionMode(RemoveActionModeCallback()) // in Single FragmentActivity
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
override fun onOptionsItemSelected(item: MenuItem) =
|
||||
actionHelper.onOptionsItemSelected(item)
|
||||
|
||||
inner class RecyclerViewAdapter internal constructor(private var glucoseValues: List<GlucoseValue>) : RecyclerView.Adapter<RecyclerViewAdapter.GlucoseValuesViewHolder>() {
|
||||
|
||||
|
@ -159,34 +145,27 @@ class BGSourceFragment : DaggerFragment() {
|
|||
if (diff < T.secs(20).msecs())
|
||||
holder.binding.root.setBackgroundColor(rh.gc(R.color.errorAlertBackground))
|
||||
}
|
||||
fun updateSelection(selected: Boolean) {
|
||||
if (selected) {
|
||||
selectedItems.put(position, glucoseValue)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
}
|
||||
|
||||
holder.binding.root.setOnLongClickListener {
|
||||
if (removeActionMode == null) {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
||||
}
|
||||
actionHelper.startRemove()
|
||||
holder.binding.cbRemove.toggle()
|
||||
updateSelection(holder.binding.cbRemove.isChecked)
|
||||
actionHelper.updateSelection(position, glucoseValue, holder.binding.cbRemove.isChecked)
|
||||
true
|
||||
}
|
||||
holder.binding.root.setOnClickListener {
|
||||
if (removeActionMode != null) {
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.toggle()
|
||||
updateSelection(holder.binding.cbRemove.isChecked)
|
||||
actionHelper.updateSelection(position, glucoseValue, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
}
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value -> updateSelection(value) }
|
||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.cbRemove.visibility = (removeActionMode != null).toVisibility()
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, glucoseValue, value)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
holder.binding.cbRemove.visibility = actionHelper.isRemoving.toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = glucoseValues.size
|
||||
override fun getItemCount() = glucoseValues.size
|
||||
|
||||
inner class GlucoseValuesViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
|
@ -194,36 +173,7 @@ class BGSourceFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<GlucoseValue>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val glucoseValue = selectedItems.valueAt(0)
|
||||
return dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits())
|
||||
|
@ -231,36 +181,33 @@ class BGSourceFragment : DaggerFragment() {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected() {
|
||||
if (selectedItems.size() > 0)
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach { _, glucoseValue ->
|
||||
val source = when ((activePlugin.activeBgSource as PluginBase).pluginDescription.pluginName) {
|
||||
R.string.dexcom_app_patched -> Sources.Dexcom
|
||||
R.string.eversense -> Sources.Eversense
|
||||
R.string.Glimp -> Sources.Glimp
|
||||
R.string.MM640g -> Sources.MM640g
|
||||
R.string.nsclientbg -> Sources.NSClientSource
|
||||
R.string.poctech -> Sources.PocTech
|
||||
R.string.tomato -> Sources.Tomato
|
||||
R.string.glunovo -> Sources.Glunovo
|
||||
R.string.xdrip -> Sources.Xdrip
|
||||
else -> Sources.Unknown
|
||||
}
|
||||
uel.log(
|
||||
Action.BG_REMOVED, source,
|
||||
ValueWithUnit.Timestamp(glucoseValue.timestamp)
|
||||
)
|
||||
repository.runTransactionForResult(InvalidateGlucoseValueTransaction(glucoseValue.id))
|
||||
.doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating BG value", it) }
|
||||
.blockingGet()
|
||||
.also { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bg $it") } }
|
||||
private fun removeSelected(selectedItems: SparseArray<GlucoseValue>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, glucoseValue ->
|
||||
val source = when ((activePlugin.activeBgSource as PluginBase).pluginDescription.pluginName) {
|
||||
R.string.dexcom_app_patched -> Sources.Dexcom
|
||||
R.string.eversense -> Sources.Eversense
|
||||
R.string.Glimp -> Sources.Glimp
|
||||
R.string.MM640g -> Sources.MM640g
|
||||
R.string.nsclientbg -> Sources.NSClientSource
|
||||
R.string.poctech -> Sources.PocTech
|
||||
R.string.tomato -> Sources.Tomato
|
||||
R.string.glunovo -> Sources.Glunovo
|
||||
R.string.xdrip -> Sources.Xdrip
|
||||
else -> Sources.Unknown
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
})
|
||||
}
|
||||
else
|
||||
removeActionMode?.finish()
|
||||
uel.log(
|
||||
Action.BG_REMOVED, source,
|
||||
ValueWithUnit.Timestamp(glucoseValue.timestamp)
|
||||
)
|
||||
repository.runTransactionForResult(InvalidateGlucoseValueTransaction(glucoseValue.id))
|
||||
.doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating BG value", it) }
|
||||
.blockingGet()
|
||||
.also { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bg $it") } }
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||
</vector>
|
||||
|
|
11
app/src/main/res/drawable/ic_sort.xml
Normal file
11
app/src/main/res/drawable/ic_sort.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z" />
|
||||
</vector>
|
|
@ -1,10 +0,0 @@
|
|||
<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:orderInCategory="0"
|
||||
android:title="@string/remove_bg_readings"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
|
@ -4,8 +4,8 @@
|
|||
<item
|
||||
android:id="@+id/remove_selected"
|
||||
android:icon="@drawable/ic_trash"
|
||||
android:iconTint="?attr/trashBinTintColor"
|
||||
android:iconTint="?attr/colorControlNormal"
|
||||
android:title="@string/remove_selected_items"
|
||||
app:showAsAction="always" />
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_plugin_preferences"
|
||||
android:orderInCategory="1"
|
||||
app:showAsAction="ifRoom"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:title="@string/nav_plugin_preferences" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -3,13 +3,15 @@ package info.nightscout.androidaps.plugins.general.automation
|
|||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import androidx.core.util.forEach
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -20,24 +22,24 @@ import info.nightscout.androidaps.automation.databinding.AutomationEventItemBind
|
|||
import info.nightscout.androidaps.automation.databinding.AutomationFragmentBinding
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
||||
import info.nightscout.androidaps.utils.dragHelpers.ItemTouchHelperAdapter
|
||||
import info.nightscout.androidaps.utils.dragHelpers.OnStartDragListener
|
||||
import info.nightscout.androidaps.utils.dragHelpers.SimpleItemTouchHelperCallback
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
||||
import info.nightscout.androidaps.utils.ActionHelper
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.OnStartDragListener
|
||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.SimpleItemTouchHelperCallback
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import java.util.*
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||
|
@ -52,11 +54,8 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private lateinit var eventListAdapter: EventListAdapter
|
||||
private var selectedItems: SparseArray<AutomationEvent> = SparseArray()
|
||||
private var removeActionMode: ActionMode? = null
|
||||
private var sortActionMode: ActionMode? = null
|
||||
private lateinit var actionHelper: ActionHelper<AutomationEvent>
|
||||
private val itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback())
|
||||
|
||||
private var _binding: AutomationFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
|
@ -64,20 +63,22 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = AutomationFragmentBinding.inflate(inflater, container, false)
|
||||
actionHelper = ActionHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.eventListView.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
actionHelper.enableSort = true
|
||||
setHasOptionsMenu(actionHelper.inMenu)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
eventListAdapter = EventListAdapter()
|
||||
binding.eventListView.layoutManager = LinearLayoutManager(context)
|
||||
binding.eventListView.adapter = eventListAdapter
|
||||
binding.logView.movementMethod = ScrollingMovementMethod()
|
||||
binding.fabAddEvent.setOnClickListener {
|
||||
removeActionMode?.finish()
|
||||
sortActionMode?.finish()
|
||||
actionHelper.finish()
|
||||
val dialog = EditEventDialog()
|
||||
val args = Bundle()
|
||||
args.putString("event", AutomationEvent(injector).toJSON())
|
||||
|
@ -110,8 +111,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
removeActionMode?.finish()
|
||||
sortActionMode?.finish()
|
||||
actionHelper.finish()
|
||||
super.onPause()
|
||||
disposable.clear()
|
||||
}
|
||||
|
@ -119,38 +119,16 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.finish()
|
||||
sortActionMode?.finish()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.menu_automation, menu)
|
||||
actionHelper.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
// Only show when tab automation is shown
|
||||
menu.findItem(R.id.nav_remove_automation_items)?.isVisible = isResumed
|
||||
menu.findItem(R.id.nav_sort_automation_items)?.isVisible = isResumed
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.nav_remove_automation_items -> {
|
||||
removeActionMode = activity?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_sort_automation_items -> {
|
||||
sortActionMode = activity?.startActionMode(SortActionModeCallback())
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
actionHelper.onOptionsItemSelected(item)
|
||||
|
||||
@Synchronized
|
||||
private fun updateGui() {
|
||||
|
@ -235,52 +213,74 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
}
|
||||
holder.binding.aapsLogo.visibility = (automation.systemAction).toVisibility()
|
||||
|
||||
fun updateSelection(selected: Boolean) {
|
||||
if (selected) {
|
||||
selectedItems.put(position, automation)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
var longPress = false
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
val mLongPressed = Runnable {
|
||||
longPress = true
|
||||
actionHelper.startAction()
|
||||
}
|
||||
|
||||
holder.binding.rootLayout.setOnTouchListener { _, touchEvent ->
|
||||
if (touchEvent.actionMasked == MotionEvent.ACTION_UP && sortActionMode == null && removeActionMode == null) {
|
||||
fun click() {
|
||||
if (actionHelper.isNoAction && !longPress) {
|
||||
val dialog = EditEventDialog()
|
||||
val args = Bundle()
|
||||
args.putString("event", automation.toJSON())
|
||||
args.putInt("position", position)
|
||||
dialog.arguments = args
|
||||
dialog.show(childFragmentManager, "EditEventDialog")
|
||||
}
|
||||
if (touchEvent.actionMasked == MotionEvent.ACTION_DOWN && sortActionMode != null) {
|
||||
onStartDrag(holder)
|
||||
}
|
||||
if (touchEvent.actionMasked == MotionEvent.ACTION_UP && removeActionMode != null) {
|
||||
} else if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.toggle()
|
||||
updateSelection(holder.binding.cbRemove.isChecked)
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
actionHelper.updateSelection(position, automation, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
}
|
||||
// Implement click listeners and touch handler for accessibility, unfortunately drag and drop for sorting can not be made accessible
|
||||
holder.binding.rootLayout.setOnClickListener {
|
||||
click()
|
||||
}
|
||||
holder.binding.rootLayout.setOnLongClickListener {
|
||||
actionHelper.startAction()
|
||||
true
|
||||
}
|
||||
holder.binding.rootLayout.setOnTouchListener { _, touchEvent ->
|
||||
when (touchEvent.actionMasked) {
|
||||
MotionEvent.ACTION_UP -> {
|
||||
handler.removeCallbacks(mLongPressed)
|
||||
click()
|
||||
longPress = false
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
if (actionHelper.isSorting) {
|
||||
onStartDrag(holder)
|
||||
}
|
||||
if (actionHelper.isNoAction && !actionHelper.inMenu) {
|
||||
handler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout().toLong())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return@setOnTouchListener true
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value -> updateSelection(value) }
|
||||
holder.binding.iconSort.visibility = (sortActionMode != null).toVisibility()
|
||||
holder.binding.cbRemove.visibility = (removeActionMode != null).toVisibility()
|
||||
holder.binding.cbRemove.isEnabled = !automation.readOnly
|
||||
holder.binding.enabled.visibility = if (removeActionMode == null) View.VISIBLE else View.INVISIBLE
|
||||
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, automation, value)
|
||||
}
|
||||
holder.binding.iconSort.visibility = actionHelper.isSorting.toVisibility()
|
||||
holder.binding.cbRemove.visibility = actionHelper.isRemoving.toVisibility()
|
||||
holder.binding.cbRemove.isEnabled = automation.readOnly.not()
|
||||
holder.binding.enabled.visibility = if (actionHelper.isRemoving) View.INVISIBLE else View.VISIBLE
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = automationPlugin.size()
|
||||
override fun getItemCount() = automationPlugin.size()
|
||||
|
||||
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
|
||||
binding.eventListView.adapter?.notifyItemMoved(fromPosition, toPosition)
|
||||
automationPlugin.swap(fromPosition, toPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDrop() {
|
||||
rxBus.send(EventAutomationDataChanged())
|
||||
}
|
||||
override fun onDrop() = rxBus.send(EventAutomationDataChanged())
|
||||
|
||||
inner class ViewHolder(view: View, val context: Context) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
|
@ -288,54 +288,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
}
|
||||
}
|
||||
|
||||
inner class SortActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.title = rh.gs(R.string.sort_label)
|
||||
binding.eventListView.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem) = false
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
sortActionMode = null
|
||||
binding.eventListView.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
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.eventListView.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.eventListView.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<AutomationEvent>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val event = selectedItems.valueAt(0)
|
||||
return rh.gs(R.string.removerecord) + " " + event.title
|
||||
|
@ -343,20 +296,17 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected() {
|
||||
if (selectedItems.size() > 0) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach { _, event ->
|
||||
uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, event.title)
|
||||
automationPlugin.removeAt(event.position)
|
||||
rxBus.send(EventAutomationDataChanged())
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
removeActionMode?.finish()
|
||||
private fun removeSelected(selectedItems: SparseArray<AutomationEvent>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, event ->
|
||||
uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, event.title)
|
||||
automationPlugin.removeAt(event.position)
|
||||
rxBus.send(EventAutomationDataChanged())
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<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_automation_items"
|
||||
android:orderInCategory="0"
|
||||
android:title="@string/remove_automation"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_sort_automation_items"
|
||||
android:orderInCategory="0"
|
||||
android:title="@string/sort_automation"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
|
@ -0,0 +1,185 @@
|
|||
package info.nightscout.androidaps.utils
|
||||
|
||||
import android.util.SparseArray
|
||||
import android.view.ActionMode
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import info.nightscout.androidaps.core.R
|
||||
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
||||
class ActionHelper<T>(val rh: ResourceHelper, val activity: FragmentActivity?) {
|
||||
|
||||
var enableSort = false
|
||||
private var selectedItems: SparseArray<T> = SparseArray()
|
||||
private var actionMode: ActionMode? = null
|
||||
private var removeActionMode: ActionMode? = null
|
||||
private var sortActionMode: ActionMode? = null
|
||||
private var onRemove: ((selectedItems: SparseArray<T>) -> Unit)? = null
|
||||
private var onUpdate: (() -> Unit)? = null
|
||||
|
||||
val inMenu: Boolean
|
||||
get() {
|
||||
val parentClass = this.activity?.let { it::class.simpleName }
|
||||
return parentClass == "SingleFragmentActivity"
|
||||
}
|
||||
|
||||
val enableRemove: Boolean
|
||||
get() = onRemove != null
|
||||
|
||||
val isNoAction: Boolean
|
||||
get() = actionMode == null && removeActionMode == null && sortActionMode == null
|
||||
|
||||
val isAction: Boolean
|
||||
get() = actionMode != null
|
||||
|
||||
val isSorting: Boolean
|
||||
get() = sortActionMode != null
|
||||
|
||||
val isRemoving: Boolean
|
||||
get() = removeActionMode != null
|
||||
|
||||
fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = activity?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_sort_items -> {
|
||||
sortActionMode = activity?.startActionMode(SortActionModeCallback())
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSelection(position: Int, item: T, selected: Boolean) {
|
||||
if (selected) {
|
||||
selectedItems.put(position, item)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
}
|
||||
|
||||
fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
if (inMenu) {
|
||||
inflater.inflate(R.menu.menu_actions, menu)
|
||||
}
|
||||
}
|
||||
|
||||
fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_remove_items)?.isVisible = enableRemove
|
||||
menu.findItem(R.id.nav_sort_items)?.isVisible = enableSort
|
||||
}
|
||||
|
||||
fun startAction() {
|
||||
if (actionMode == null) {
|
||||
actionMode = activity?.startActionMode(ActionModeCallback())
|
||||
}
|
||||
}
|
||||
|
||||
fun startRemove() {
|
||||
if (removeActionMode == null) {
|
||||
removeActionMode = activity?.startActionMode(RemoveActionModeCallback())
|
||||
}
|
||||
}
|
||||
|
||||
fun startSort() {
|
||||
if (sortActionMode == null) {
|
||||
sortActionMode = activity?.startActionMode(SortActionModeCallback())
|
||||
}
|
||||
}
|
||||
|
||||
fun isSelected(position: Int) =
|
||||
selectedItems.get(position) != null
|
||||
|
||||
fun setOnRemoveHandler(onRemove: (selectedItems: SparseArray<T>) -> Unit) {
|
||||
this.onRemove = onRemove
|
||||
}
|
||||
|
||||
fun setUpdateListHandler(onUpdate: () -> Unit) {
|
||||
this.onUpdate = onUpdate
|
||||
}
|
||||
|
||||
fun finish() {
|
||||
actionMode?.finish()
|
||||
removeActionMode?.finish()
|
||||
sortActionMode?.finish()
|
||||
}
|
||||
|
||||
private inner class ActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.title = activity?.title
|
||||
mode.menuInflater.inflate(R.menu.menu_actions, menu)
|
||||
onUpdate?.let { it() }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem) =
|
||||
onOptionsItemSelected(item)
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
actionMode = null
|
||||
}
|
||||
}
|
||||
|
||||
private inner class SortActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.title = rh.gs(R.string.sort_label)
|
||||
onUpdate?.let { it() }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem) = false
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
sortActionMode = null
|
||||
onUpdate?.let { it() }
|
||||
}
|
||||
}
|
||||
|
||||
private 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())
|
||||
onUpdate?.let { it() }
|
||||
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 -> {
|
||||
if (selectedItems.size() > 0) {
|
||||
onRemove?.let { it(selectedItems) }
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
removeActionMode = null
|
||||
onUpdate?.let { it() }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
core/src/main/res/drawable/ic_sort.xml
Normal file
11
core/src/main/res/drawable/ic_sort.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z" />
|
||||
</vector>
|
10
core/src/main/res/drawable/ic_trash.xml
Normal file
10
core/src/main/res/drawable/ic_trash.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:pathData="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z" />
|
||||
</vector>
|
|
@ -1,14 +1,19 @@
|
|||
<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>
|
||||
<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:icon="@drawable/ic_trash"
|
||||
android:iconTint="?attr/colorControlNormal"
|
||||
android:orderInCategory="0"
|
||||
android:title="@string/remove_items"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_sort_items"
|
||||
android:icon="@drawable/ic_sort"
|
||||
android:orderInCategory="0"
|
||||
android:title="@string/sort_items"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
|
@ -4,8 +4,8 @@
|
|||
<item
|
||||
android:id="@+id/remove_selected"
|
||||
android:icon="@drawable/ic_trash"
|
||||
android:iconTint="@color/white"
|
||||
android:iconTint="?attr/colorControlNormal"
|
||||
android:title="@string/remove_selected_items"
|
||||
app:showAsAction="always" />
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
</menu>
|
|
@ -556,6 +556,11 @@
|
|||
<string name="formatPercent">%1$.0f%%</string>
|
||||
<string name="basal">Basal</string>
|
||||
<string name="basalpct">Basal %</string>
|
||||
<string name="count_selected">%1$d selected</string>
|
||||
<string name="sort_label">Sort</string>
|
||||
<string name="remove_items">Remove Items</string>
|
||||
<string name="sort_items">Sort Items</string>
|
||||
<string name="remove_selected_items">Remove Selected Items</string>
|
||||
|
||||
<plurals name="days">
|
||||
<item quantity="one">%1$d day</item>
|
||||
|
|
Loading…
Reference in a new issue