Merge pull request #1511 from Andries-Smit/chore/shared-action-helper
chore: Unified experience for sort and delete in QuickWizard, BG Source, Automation and treatments
This commit is contained in:
commit
fa2543bc7c
45 changed files with 974 additions and 1050 deletions
|
@ -5,9 +5,6 @@ import android.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.CompoundButton
|
|
||||||
import android.view.ActionMode
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -38,9 +35,11 @@ import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||||
|
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -71,8 +70,10 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
@Inject lateinit var activePlugin: ActivePlugin
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
|
|
||||||
private var _binding: TreatmentsBolusCarbsFragmentBinding? = null
|
private var _binding: TreatmentsBolusCarbsFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var menu: Menu? = null
|
||||||
|
|
||||||
class MealLink(
|
class MealLink(
|
||||||
val bolus: Bolus? = null,
|
val bolus: Bolus? = null,
|
||||||
|
@ -81,21 +82,22 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
)
|
)
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
private lateinit var actionHelper: ActionModeHelper<MealLink>
|
||||||
private val millsToThePast = T.days(30).msecs()
|
private val millsToThePast = T.days(30).msecs()
|
||||||
|
|
||||||
private var selectedItems: SparseArray<MealLink> = SparseArray()
|
// private var selectedItems: SparseArray<MealLink> = SparseArray()
|
||||||
private var showInvalidated = false
|
private var showInvalidated = false
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
private var toolbar: Toolbar? = null
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
TreatmentsBolusCarbsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
TreatmentsBolusCarbsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
toolbar = activity?.findViewById(R.id.toolbar)
|
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
}
|
}
|
||||||
|
@ -183,13 +185,13 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
actionHelper.finish()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
binding.recyclerview.adapter = null // avoid leaks
|
binding.recyclerview.adapter = null // avoid leaks
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
@ -243,6 +245,17 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
Bolus.Type.NORMAL -> rh.gs(R.string.mealbolus)
|
Bolus.Type.NORMAL -> rh.gs(R.string.mealbolus)
|
||||||
Bolus.Type.PRIMING -> rh.gs(R.string.prime)
|
Bolus.Type.PRIMING -> rh.gs(R.string.prime)
|
||||||
}
|
}
|
||||||
|
holder.binding.cbBolusRemove.visibility = (ml.bolus.isValid && actionHelper.isRemoving).toVisibility()
|
||||||
|
if (actionHelper.isRemoving) {
|
||||||
|
holder.binding.cbBolusRemove.setOnCheckedChangeListener { _, value ->
|
||||||
|
actionHelper.updateSelection(position, ml, value)
|
||||||
|
}
|
||||||
|
holder.binding.root.setOnClickListener {
|
||||||
|
holder.binding.cbBolusRemove.toggle()
|
||||||
|
actionHelper.updateSelection(position, ml, holder.binding.cbBolusRemove.isChecked)
|
||||||
|
}
|
||||||
|
holder.binding.cbBolusRemove.isChecked = actionHelper.isSelected(position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Carbs
|
// Carbs
|
||||||
holder.binding.carbsLayout.visibility = (ml.carbs != null && (ml.carbs.isValid || showInvalidated)).toVisibility()
|
holder.binding.carbsLayout.visibility = (ml.carbs != null && (ml.carbs.isValid || showInvalidated)).toVisibility()
|
||||||
|
@ -253,23 +266,19 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
holder.binding.carbsNs.visibility = (carbs.interfaceIDs.nightscoutId != null).toVisibility()
|
holder.binding.carbsNs.visibility = (carbs.interfaceIDs.nightscoutId != null).toVisibility()
|
||||||
holder.binding.carbsPump.visibility = (carbs.interfaceIDs.pumpId != null).toVisibility()
|
holder.binding.carbsPump.visibility = (carbs.interfaceIDs.pumpId != null).toVisibility()
|
||||||
holder.binding.carbsInvalid.visibility = carbs.isValid.not().toVisibility()
|
holder.binding.carbsInvalid.visibility = carbs.isValid.not().toVisibility()
|
||||||
|
holder.binding.cbCarbsRemove.visibility = (ml.carbs.isValid && actionHelper.isRemoving).toVisibility()
|
||||||
|
if (actionHelper.isRemoving) {
|
||||||
|
holder.binding.cbCarbsRemove.setOnCheckedChangeListener { _, value ->
|
||||||
|
actionHelper.updateSelection(position, ml, value)
|
||||||
}
|
}
|
||||||
holder.binding.cbBolusRemove.visibility = (ml.bolus?.isValid == true && removeActionMode != null).toVisibility()
|
holder.binding.root.setOnClickListener {
|
||||||
holder.binding.cbCarbsRemove.visibility = (ml.carbs?.isValid == true && removeActionMode != null).toVisibility()
|
holder.binding.cbBolusRemove.toggle()
|
||||||
if (removeActionMode != null) {
|
actionHelper.updateSelection(position, ml, holder.binding.cbBolusRemove.isChecked)
|
||||||
val onChange = CompoundButton.OnCheckedChangeListener { _, value ->
|
|
||||||
if (value) {
|
|
||||||
selectedItems.put(position, ml)
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(position)
|
|
||||||
}
|
}
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
holder.binding.cbCarbsRemove.isChecked = actionHelper.isSelected(position)
|
||||||
}
|
}
|
||||||
holder.binding.cbBolusRemove.setOnCheckedChangeListener(onChange)
|
|
||||||
holder.binding.cbBolusRemove.isChecked = selectedItems.get(position) != null
|
|
||||||
holder.binding.cbCarbsRemove.setOnCheckedChangeListener(onChange)
|
|
||||||
holder.binding.cbCarbsRemove.isChecked = selectedItems.get(position) != null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.binding.calculation.tag = ml
|
holder.binding.calculation.tag = ml
|
||||||
val nextTimestamp = if (mealLinks.size != position + 1) timestamp(mealLinks[position + 1]) else 0L
|
val nextTimestamp = if (mealLinks.size != position + 1) timestamp(mealLinks[position + 1]) else 0L
|
||||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(timestamp(ml), nextTimestamp).toVisibility()
|
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(timestamp(ml), nextTimestamp).toVisibility()
|
||||||
|
@ -297,13 +306,18 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
this.menu = menu
|
||||||
inflater.inflate(R.menu.menu_treatments_carbs_bolus, menu)
|
inflater.inflate(R.menu.menu_treatments_carbs_bolus, menu)
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateMenuVisibility() {
|
||||||
|
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||||
|
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
updateMenuVisibility()
|
||||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
|
||||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_insulin, false) || !sp.getBoolean(R.string.key_ns_receive_carbs, false) || !buildHelper.isEngineeringMode()
|
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_insulin, false) || !sp.getBoolean(R.string.key_ns_receive_carbs, false) || !buildHelper.isEngineeringMode()
|
||||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||||
val hasItems = (binding.recyclerview.adapter?.itemCount ?: 0) > 0
|
val hasItems = (binding.recyclerview.adapter?.itemCount ?: 0) > 0
|
||||||
|
@ -314,19 +328,20 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.nav_remove_items -> {
|
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_show_invalidated -> {
|
R.id.nav_show_invalidated -> {
|
||||||
showInvalidated = true
|
showInvalidated = true
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_hide_invalidated -> {
|
R.id.nav_hide_invalidated -> {
|
||||||
showInvalidated = false
|
showInvalidated = false
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -423,36 +438,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
private fun getConfirmationText(selectedItems: SparseArray<MealLink>): String {
|
||||||
|
|
||||||
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 {
|
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
val mealLink = selectedItems.valueAt(0)
|
val mealLink = selectedItems.valueAt(0)
|
||||||
val bolus = mealLink.bolus
|
val bolus = mealLink.bolus
|
||||||
|
@ -467,10 +453,9 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<MealLink>) {
|
||||||
if (selectedItems.size() > 0)
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach { _, ml ->
|
selectedItems.forEach { _, ml ->
|
||||||
ml.bolus?.let { bolus ->
|
ml.bolus?.let { bolus ->
|
||||||
uel.log(
|
uel.log(
|
||||||
|
@ -497,10 +482,9 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,39 +3,34 @@ package info.nightscout.androidaps.activities.fragments
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.ActionMode
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
|
||||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
|
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.transactions.InvalidateAAPSStartedTherapyEventTransaction
|
import info.nightscout.androidaps.database.transactions.InvalidateAAPSStartedTherapyEventTransaction
|
||||||
import info.nightscout.androidaps.database.transactions.InvalidateTherapyEventTransaction
|
import info.nightscout.androidaps.database.transactions.InvalidateTherapyEventTransaction
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBinding
|
import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBinding
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding
|
import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding
|
||||||
import info.nightscout.androidaps.events.EventTherapyEventChange
|
import info.nightscout.androidaps.events.EventTherapyEventChange
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.shared.logging.LTag
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
import info.nightscout.androidaps.utils.*
|
||||||
import info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.Translator
|
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import io.reactivex.rxjava3.core.Completable
|
import io.reactivex.rxjava3.core.Completable
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
|
@ -59,23 +54,23 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var _binding: TreatmentsCareportalFragmentBinding? = null
|
private var _binding: TreatmentsCareportalFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var menu: Menu? = null
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
private val millsToThePast = T.days(30).msecs()
|
private val millsToThePast = T.days(30).msecs()
|
||||||
private var selectedItems: SparseArray<TherapyEvent> = SparseArray()
|
private lateinit var actionHelper: ActionModeHelper<TherapyEvent>
|
||||||
private var showInvalidated = false
|
private var showInvalidated = false
|
||||||
private var toolbar: Toolbar? = null
|
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
TreatmentsCareportalFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
TreatmentsCareportalFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
toolbar = activity?.findViewById(R.id.toolbar)
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
|
@ -143,13 +138,13 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
actionHelper.finish()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
binding.recyclerview.adapter = null // avoid leaks
|
binding.recyclerview.adapter = null // avoid leaks
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
@ -172,18 +167,15 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
||||||
holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else dateUtil.niceTimeScalar(therapyEvent.duration, rh)
|
holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else dateUtil.niceTimeScalar(therapyEvent.duration, rh)
|
||||||
holder.binding.note.text = therapyEvent.note
|
holder.binding.note.text = therapyEvent.note
|
||||||
holder.binding.type.text = translator.translate(therapyEvent.type)
|
holder.binding.type.text = translator.translate(therapyEvent.type)
|
||||||
holder.binding.cbRemove.visibility = (therapyEvent.isValid && removeActionMode != null).toVisibility()
|
holder.binding.cbRemove.visibility = (therapyEvent.isValid && actionHelper.isRemoving).toVisibility()
|
||||||
if (removeActionMode != null) {
|
|
||||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||||
if (value) {
|
actionHelper.updateSelection(position, therapyEvent, value)
|
||||||
selectedItems.put(position, therapyEvent)
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(position)
|
|
||||||
}
|
}
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
holder.binding.root.setOnClickListener {
|
||||||
}
|
holder.binding.cbRemove.toggle()
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
actionHelper.updateSelection(position, therapyEvent, holder.binding.cbRemove.isChecked)
|
||||||
}
|
}
|
||||||
|
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||||
val nextTimestamp = if (therapyList.size != position + 1) therapyList[position + 1].timestamp else 0L
|
val nextTimestamp = if (therapyList.size != position + 1) therapyList[position + 1].timestamp else 0L
|
||||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(therapyEvent.timestamp, nextTimestamp).toVisibility()
|
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(therapyEvent.timestamp, nextTimestamp).toVisibility()
|
||||||
}
|
}
|
||||||
|
@ -198,34 +190,40 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
this.menu = menu
|
||||||
inflater.inflate(R.menu.menu_treatments_careportal, menu)
|
inflater.inflate(R.menu.menu_treatments_careportal, menu)
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
updateMenuVisibility()
|
||||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
|
||||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || !buildHelper.isEngineeringMode()
|
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || !buildHelper.isEngineeringMode()
|
||||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||||
|
|
||||||
return super.onPrepareOptionsMenu(menu)
|
return super.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateMenuVisibility() {
|
||||||
|
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||||
|
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.nav_remove_items -> {
|
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_show_invalidated -> {
|
R.id.nav_show_invalidated -> {
|
||||||
showInvalidated = true
|
showInvalidated = true
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_hide_invalidated -> {
|
R.id.nav_hide_invalidated -> {
|
||||||
showInvalidated = false
|
showInvalidated = false
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -243,36 +241,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
private fun getConfirmationText(selectedItems: SparseArray<TherapyEvent>): String {
|
||||||
|
|
||||||
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 {
|
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
val therapyEvent = selectedItems.valueAt(0)
|
val therapyEvent = selectedItems.valueAt(0)
|
||||||
return rh.gs(R.string.eventtype) + ": " + translator.translate(therapyEvent.type) + "\n" +
|
return rh.gs(R.string.eventtype) + ": " + translator.translate(therapyEvent.type) + "\n" +
|
||||||
|
@ -282,10 +251,9 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<TherapyEvent>) {
|
||||||
if (selectedItems.size() > 0)
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach { _, therapyEvent ->
|
selectedItems.forEach { _, therapyEvent ->
|
||||||
uel.log(
|
uel.log(
|
||||||
Action.CAREPORTAL_REMOVED, Sources.Treatments, therapyEvent.note,
|
Action.CAREPORTAL_REMOVED, Sources.Treatments, therapyEvent.note,
|
||||||
|
@ -298,11 +266,9 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
||||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) }
|
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package info.nightscout.androidaps.activities.fragments
|
package info.nightscout.androidaps.activities.fragments
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.ActionMode
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
|
@ -20,25 +20,26 @@ import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusT
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusFragmentBinding
|
import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusFragmentBinding
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusItemBinding
|
import info.nightscout.androidaps.databinding.TreatmentsExtendedbolusItemBinding
|
||||||
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
||||||
|
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.extensions.iobCalc
|
import info.nightscout.androidaps.extensions.iobCalc
|
||||||
import info.nightscout.androidaps.extensions.isInProgress
|
import info.nightscout.androidaps.extensions.isInProgress
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import info.nightscout.shared.logging.LTag
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -60,20 +61,23 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
|
||||||
private var _binding: TreatmentsExtendedbolusFragmentBinding? = null
|
private var _binding: TreatmentsExtendedbolusFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var menu: Menu? = null
|
||||||
private var selectedItems: SparseArray<ExtendedBolus> = SparseArray()
|
private lateinit var actionHelper: ActionModeHelper<ExtendedBolus>
|
||||||
private var showInvalidated = false
|
private var showInvalidated = false
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
private var toolbar: Toolbar? = null
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
TreatmentsExtendedbolusFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
TreatmentsExtendedbolusFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
toolbar = activity?.findViewById(R.id.toolbar)
|
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
}
|
}
|
||||||
|
@ -96,24 +100,28 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
swapAdapter()
|
swapAdapter()
|
||||||
|
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventExtendedBolusChange::class.java)
|
.toObservable(EventExtendedBolusChange::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.debounce(1L, TimeUnit.SECONDS)
|
.debounce(1L, TimeUnit.SECONDS)
|
||||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.debounce(1L, TimeUnit.SECONDS)
|
||||||
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
actionHelper.finish()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
binding.recyclerview.adapter = null // avoid leaks
|
binding.recyclerview.adapter = null // avoid leaks
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
@ -147,17 +155,16 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
holder.binding.iob.text = rh.gs(R.string.formatinsulinunits, iob.iob)
|
holder.binding.iob.text = rh.gs(R.string.formatinsulinunits, iob.iob)
|
||||||
holder.binding.ratio.text = rh.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
holder.binding.ratio.text = rh.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
||||||
if (iob.iob != 0.0) holder.binding.iob.setTextColor(rh.gac(context , R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.insulin.currentTextColor)
|
if (iob.iob != 0.0) holder.binding.iob.setTextColor(rh.gac(context , R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.insulin.currentTextColor)
|
||||||
holder.binding.cbRemove.visibility = (extendedBolus.isValid && removeActionMode != null).toVisibility()
|
holder.binding.cbRemove.visibility = (extendedBolus.isValid && actionHelper.isRemoving).toVisibility()
|
||||||
if (removeActionMode != null) {
|
if (actionHelper.isRemoving) {
|
||||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||||
if (value) {
|
actionHelper.updateSelection(position, extendedBolus, value)
|
||||||
selectedItems.put(position, extendedBolus)
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(position)
|
|
||||||
}
|
}
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
holder.binding.root.setOnClickListener {
|
||||||
|
holder.binding.cbRemove.toggle()
|
||||||
|
actionHelper.updateSelection(position, extendedBolus, holder.binding.cbRemove.isChecked)
|
||||||
}
|
}
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||||
}
|
}
|
||||||
val nextTimestamp = if (extendedBolusList.size != position + 1) extendedBolusList[position + 1].timestamp else 0L
|
val nextTimestamp = if (extendedBolusList.size != position + 1) extendedBolusList[position + 1].timestamp else 0L
|
||||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(extendedBolus.timestamp, nextTimestamp).toVisibility()
|
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(extendedBolus.timestamp, nextTimestamp).toVisibility()
|
||||||
|
@ -173,32 +180,37 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
this.menu = menu
|
||||||
inflater.inflate(R.menu.menu_treatments_extended_bolus, menu)
|
inflater.inflate(R.menu.menu_treatments_extended_bolus, menu)
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
private fun updateMenuVisibility() {
|
||||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
|
updateMenuVisibility()
|
||||||
return super.onPrepareOptionsMenu(menu)
|
return super.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.nav_remove_items -> {
|
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_show_invalidated -> {
|
R.id.nav_show_invalidated -> {
|
||||||
showInvalidated = true
|
showInvalidated = true
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_hide_invalidated -> {
|
R.id.nav_hide_invalidated -> {
|
||||||
showInvalidated = false
|
showInvalidated = false
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -207,36 +219,7 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
private fun getConfirmationText(selectedItems: SparseArray<ExtendedBolus>): String {
|
||||||
|
|
||||||
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 {
|
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
val bolus = selectedItems.valueAt(0)
|
val bolus = selectedItems.valueAt(0)
|
||||||
return rh.gs(R.string.extended_bolus) + "\n" +
|
return rh.gs(R.string.extended_bolus) + "\n" +
|
||||||
|
@ -245,10 +228,9 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<ExtendedBolus>) {
|
||||||
if (selectedItems.size() > 0)
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach { _, extendedBolus ->
|
selectedItems.forEach { _, extendedBolus ->
|
||||||
uel.log(
|
uel.log(
|
||||||
Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments,
|
Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments,
|
||||||
|
@ -262,10 +244,9 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
||||||
{ aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") },
|
{ aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") },
|
||||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) })
|
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) })
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package info.nightscout.androidaps.activities.fragments
|
package info.nightscout.androidaps.activities.fragments
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.ActionMode
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -32,9 +31,11 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||||
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
|
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
|
||||||
|
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -46,6 +47,7 @@ import io.reactivex.rxjava3.core.Completable
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
|
@ -63,24 +65,25 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
@Inject lateinit var uel: UserEntryLogger
|
@Inject lateinit var uel: UserEntryLogger
|
||||||
|
|
||||||
private var _binding: TreatmentsProfileswitchFragmentBinding? = null
|
private var _binding: TreatmentsProfileswitchFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var menu: Menu? = null
|
||||||
|
private lateinit var actionHelper: ActionModeHelper<ProfileSealed>
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
private val millsToThePast = T.days(30).msecs()
|
private val millsToThePast = T.days(30).msecs()
|
||||||
private var selectedItems: SparseArray<ProfileSealed> = SparseArray()
|
|
||||||
private var showInvalidated = false
|
private var showInvalidated = false
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
private var toolbar: Toolbar? = null
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
TreatmentsProfileswitchFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
TreatmentsProfileswitchFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
toolbar = activity?.findViewById(R.id.toolbar)
|
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
}
|
}
|
||||||
|
@ -159,18 +162,23 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
|
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.debounce(1L, TimeUnit.SECONDS)
|
||||||
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
actionHelper.finish()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
binding.recyclerview.adapter = null // avoid leaks
|
binding.recyclerview.adapter = null // avoid leaks
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
@ -198,17 +206,16 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
holder.binding.date.tag = profileSwitch
|
holder.binding.date.tag = profileSwitch
|
||||||
holder.binding.invalid.visibility = profileSwitch.isValid.not().toVisibility()
|
holder.binding.invalid.visibility = profileSwitch.isValid.not().toVisibility()
|
||||||
holder.binding.duration.visibility = (profileSwitch.duration != 0L && profileSwitch.duration != null).toVisibility()
|
holder.binding.duration.visibility = (profileSwitch.duration != 0L && profileSwitch.duration != null).toVisibility()
|
||||||
holder.binding.cbRemove.visibility = (removeActionMode != null && profileSwitch is ProfileSealed.PS).toVisibility()
|
holder.binding.cbRemove.visibility = (actionHelper.isRemoving && profileSwitch is ProfileSealed.PS).toVisibility()
|
||||||
if (removeActionMode != null) {
|
if (actionHelper.isRemoving) {
|
||||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||||
if (value) {
|
actionHelper.updateSelection(position, profileSwitch, value)
|
||||||
selectedItems.put(position, profileSwitch)
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(position)
|
|
||||||
}
|
}
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
holder.binding.root.setOnClickListener {
|
||||||
|
holder.binding.cbRemove.toggle()
|
||||||
|
actionHelper.updateSelection(position, profileSwitch, holder.binding.cbRemove.isChecked)
|
||||||
}
|
}
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||||
}
|
}
|
||||||
holder.binding.clone.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
|
holder.binding.clone.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
|
||||||
holder.binding.spacer.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
|
holder.binding.spacer.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
|
||||||
|
@ -273,13 +280,18 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
this.menu = menu
|
||||||
inflater.inflate(R.menu.menu_treatments_profile_switch, menu)
|
inflater.inflate(R.menu.menu_treatments_profile_switch, menu)
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateMenuVisibility() {
|
||||||
|
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||||
|
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
updateMenuVisibility()
|
||||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
|
||||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || !buildHelper.isEngineeringMode()
|
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || !buildHelper.isEngineeringMode()
|
||||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||||
|
|
||||||
|
@ -288,19 +300,20 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.nav_remove_items -> {
|
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_show_invalidated -> {
|
R.id.nav_show_invalidated -> {
|
||||||
showInvalidated = true
|
showInvalidated = true
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_hide_invalidated -> {
|
R.id.nav_hide_invalidated -> {
|
||||||
showInvalidated = false
|
showInvalidated = false
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -313,36 +326,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
private fun getConfirmationText(selectedItems: SparseArray<ProfileSealed>): String {
|
||||||
|
|
||||||
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 {
|
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
val profileSwitch = selectedItems.valueAt(0)
|
val profileSwitch = selectedItems.valueAt(0)
|
||||||
return rh.gs(R.string.careportal_profileswitch) + ": " + profileSwitch.profileName + "\n" + rh.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(profileSwitch.timestamp)
|
return rh.gs(R.string.careportal_profileswitch) + ": " + profileSwitch.profileName + "\n" + rh.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(profileSwitch.timestamp)
|
||||||
|
@ -350,10 +334,9 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<ProfileSealed>) {
|
||||||
if (selectedItems.size() > 0)
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach { _, profileSwitch ->
|
selectedItems.forEach { _, profileSwitch ->
|
||||||
uel.log(
|
uel.log(
|
||||||
Action.PROFILE_SWITCH_REMOVED, Sources.Treatments, profileSwitch.profileName,
|
Action.PROFILE_SWITCH_REMOVED, Sources.Treatments, profileSwitch.profileName,
|
||||||
|
@ -365,10 +348,8 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
||||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating ProfileSwitch", it) }
|
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating ProfileSwitch", it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,46 +4,42 @@ import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
|
||||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
|
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||||
import info.nightscout.androidaps.database.interfaces.end
|
import info.nightscout.androidaps.database.interfaces.end
|
||||||
import info.nightscout.androidaps.database.transactions.InvalidateTemporaryTargetTransaction
|
import info.nightscout.androidaps.database.transactions.InvalidateTemporaryTargetTransaction
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsTemptargetFragmentBinding
|
import info.nightscout.androidaps.databinding.TreatmentsTemptargetFragmentBinding
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding
|
import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding
|
||||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
|
||||||
import info.nightscout.shared.logging.LTag
|
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
|
||||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
|
||||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
|
||||||
import info.nightscout.androidaps.events.EventEffectiveProfileSwitchChanged
|
import info.nightscout.androidaps.events.EventEffectiveProfileSwitchChanged
|
||||||
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.utils.T
|
|
||||||
import info.nightscout.androidaps.utils.Translator
|
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
|
||||||
import info.nightscout.androidaps.extensions.friendlyDescription
|
import info.nightscout.androidaps.extensions.friendlyDescription
|
||||||
import info.nightscout.androidaps.extensions.highValueToUnitsToString
|
import info.nightscout.androidaps.extensions.highValueToUnitsToString
|
||||||
import info.nightscout.androidaps.extensions.lowValueToUnitsToString
|
import info.nightscout.androidaps.extensions.lowValueToUnitsToString
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||||
|
import info.nightscout.androidaps.utils.*
|
||||||
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import io.reactivex.rxjava3.core.Completable
|
import io.reactivex.rxjava3.core.Completable
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
|
@ -68,22 +64,24 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
|
||||||
private var _binding: TreatmentsTemptargetFragmentBinding? = null
|
private var _binding: TreatmentsTemptargetFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var menu: Menu? = null
|
||||||
|
private lateinit var actionHelper: ActionModeHelper<TemporaryTarget>
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
private val millsToThePast = T.days(30).msecs()
|
private val millsToThePast = T.days(30).msecs()
|
||||||
private var selectedItems: SparseArray<TemporaryTarget> = SparseArray()
|
|
||||||
private var showInvalidated = false
|
private var showInvalidated = false
|
||||||
private var toolbar: Toolbar? = null
|
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
TreatmentsTemptargetFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
TreatmentsTemptargetFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
toolbar = activity?.findViewById(R.id.toolbar)
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
}
|
}
|
||||||
|
@ -131,13 +129,11 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
swapAdapter()
|
swapAdapter()
|
||||||
|
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventTempTargetChange::class.java)
|
.toObservable(EventTempTargetChange::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
.debounce(1L, TimeUnit.SECONDS)
|
.debounce(1L, TimeUnit.SECONDS)
|
||||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
|
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
|
@ -148,13 +144,13 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
actionHelper.finish()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
binding.recyclerview.adapter = null // avoid leaks
|
binding.recyclerview.adapter = null // avoid leaks
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
@ -173,17 +169,16 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
val tempTarget = tempTargetList[position]
|
val tempTarget = tempTargetList[position]
|
||||||
holder.binding.ns.visibility = (tempTarget.interfaceIDs.nightscoutId != null).toVisibility()
|
holder.binding.ns.visibility = (tempTarget.interfaceIDs.nightscoutId != null).toVisibility()
|
||||||
holder.binding.invalid.visibility = tempTarget.isValid.not().toVisibility()
|
holder.binding.invalid.visibility = tempTarget.isValid.not().toVisibility()
|
||||||
holder.binding.cbRemove.visibility = (tempTarget.isValid && removeActionMode != null).toVisibility()
|
holder.binding.cbRemove.visibility = (tempTarget.isValid && actionHelper.isRemoving).toVisibility()
|
||||||
if (removeActionMode != null) {
|
if (actionHelper.isRemoving) {
|
||||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||||
if (value) {
|
actionHelper.updateSelection(position, tempTarget, value)
|
||||||
selectedItems.put(position, tempTarget)
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(position)
|
|
||||||
}
|
}
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
holder.binding.root.setOnClickListener {
|
||||||
|
holder.binding.cbRemove.toggle()
|
||||||
|
actionHelper.updateSelection(position, tempTarget, holder.binding.cbRemove.isChecked)
|
||||||
}
|
}
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||||
}
|
}
|
||||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(tempTarget.timestamp, tempTargetList[position - 1].timestamp)
|
val newDay = position == 0 || !dateUtil.isSameDayGroup(tempTarget.timestamp, tempTargetList[position - 1].timestamp)
|
||||||
holder.binding.date.visibility = newDay.toVisibility()
|
holder.binding.date.visibility = newDay.toVisibility()
|
||||||
|
@ -213,10 +208,65 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
if (selectedItems.size() > 0)
|
this.menu = menu
|
||||||
|
inflater.inflate(R.menu.menu_treatments_temp_target, menu)
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateMenuVisibility() {
|
||||||
|
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||||
|
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
|
updateMenuVisibility()
|
||||||
|
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_temp_target, false) || !buildHelper.isEngineeringMode()
|
||||||
|
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||||
|
|
||||||
|
return super.onPrepareOptionsMenu(menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||||
|
|
||||||
|
R.id.nav_show_invalidated -> {
|
||||||
|
showInvalidated = true
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||||
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.nav_hide_invalidated -> {
|
||||||
|
showInvalidated = false
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||||
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.nav_refresh_ns -> {
|
||||||
|
refreshFromNightscout()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getConfirmationText(selectedItems: SparseArray<TemporaryTarget>): String {
|
||||||
|
if (selectedItems.size() == 1) {
|
||||||
|
val tempTarget = selectedItems.valueAt(0)
|
||||||
|
return "${rh.gs(R.string.careportal_temporarytarget)}: ${tempTarget.friendlyDescription(profileFunction.getUnits(), rh)}\n" +
|
||||||
|
dateUtil.dateAndTimeString(tempTarget.timestamp)
|
||||||
|
}
|
||||||
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeSelected(selectedItems: SparseArray<TemporaryTarget>) {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach { _, tempTarget ->
|
selectedItems.forEach { _, tempTarget ->
|
||||||
uel.log(
|
uel.log(
|
||||||
Action.TT_REMOVED, Sources.Treatments,
|
Action.TT_REMOVED, Sources.Treatments,
|
||||||
|
@ -231,90 +281,9 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
||||||
{ aapsLogger.debug(LTag.DATABASE, "Removed temp target $tempTarget") },
|
{ aapsLogger.debug(LTag.DATABASE, "Removed temp target $tempTarget") },
|
||||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it) })
|
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it) })
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
|
||||||
inflater.inflate(R.menu.menu_treatments_temp_target, menu)
|
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
|
||||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
|
||||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
|
||||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_temp_target, false) || !buildHelper.isEngineeringMode()
|
|
||||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
|
||||||
|
|
||||||
return super.onPrepareOptionsMenu(menu)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.nav_remove_items -> {
|
|
||||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_show_invalidated -> {
|
|
||||||
showInvalidated = true
|
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_hide_invalidated -> {
|
|
||||||
showInvalidated = false
|
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_refresh_ns -> {
|
|
||||||
refreshFromNightscout()
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getConfirmationText(): String {
|
|
||||||
if (selectedItems.size() == 1) {
|
|
||||||
val tempTarget = selectedItems.valueAt(0)
|
|
||||||
return "${rh.gs(R.string.careportal_temporarytarget)}: ${tempTarget.friendlyDescription(profileFunction.getUnits(), rh)}\n" +
|
|
||||||
dateUtil.dateAndTimeString(tempTarget.timestamp)
|
|
||||||
}
|
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
package info.nightscout.androidaps.activities.fragments
|
package info.nightscout.androidaps.activities.fragments
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
||||||
import info.nightscout.androidaps.data.IobTotal
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.database.ValueWrapper
|
import info.nightscout.androidaps.database.ValueWrapper
|
||||||
|
@ -24,24 +25,25 @@ import info.nightscout.androidaps.databinding.TreatmentsTempbasalsFragmentBindin
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsItemBinding
|
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsItemBinding
|
||||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||||
import info.nightscout.androidaps.events.EventTempBasalChange
|
import info.nightscout.androidaps.events.EventTempBasalChange
|
||||||
|
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||||
import info.nightscout.androidaps.extensions.iobCalc
|
import info.nightscout.androidaps.extensions.iobCalc
|
||||||
import info.nightscout.androidaps.extensions.toStringFull
|
import info.nightscout.androidaps.extensions.toStringFull
|
||||||
import info.nightscout.androidaps.extensions.toTemporaryBasal
|
import info.nightscout.androidaps.extensions.toTemporaryBasal
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
|
||||||
import info.nightscout.shared.logging.LTag
|
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -64,21 +66,23 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
@Inject lateinit var repository: AppRepository
|
@Inject lateinit var repository: AppRepository
|
||||||
|
|
||||||
private var _binding: TreatmentsTempbasalsFragmentBinding? = null
|
private var _binding: TreatmentsTempbasalsFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
private var menu: Menu? = null
|
||||||
|
private lateinit var actionHelper: ActionModeHelper<TemporaryBasal>
|
||||||
private val millsToThePast = T.days(30).msecs()
|
private val millsToThePast = T.days(30).msecs()
|
||||||
private var selectedItems: SparseArray<TemporaryBasal> = SparseArray()
|
|
||||||
private var showInvalidated = false
|
private var showInvalidated = false
|
||||||
private var toolbar: Toolbar? = null
|
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
TreatmentsTempbasalsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
TreatmentsTempbasalsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
toolbar = activity?.findViewById(R.id.toolbar)
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
|
@ -133,28 +137,31 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
swapAdapter()
|
swapAdapter()
|
||||||
|
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventTempBasalChange::class.java)
|
.toObservable(EventTempBasalChange::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
|
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.debounce(1L, TimeUnit.SECONDS)
|
||||||
|
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
actionHelper.finish()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
binding.recyclerview.adapter = null // avoid leaks
|
binding.recyclerview.adapter = null // avoid leaks
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
@ -194,17 +201,16 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
holder.binding.emulatedSuspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.EMULATED_PUMP_SUSPEND).toVisibility()
|
holder.binding.emulatedSuspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.EMULATED_PUMP_SUSPEND).toVisibility()
|
||||||
holder.binding.superBolusFlag.visibility = (tempBasal.type == TemporaryBasal.Type.SUPERBOLUS).toVisibility()
|
holder.binding.superBolusFlag.visibility = (tempBasal.type == TemporaryBasal.Type.SUPERBOLUS).toVisibility()
|
||||||
if (abs(iob.basaliob) > 0.01) holder.binding.iob.setTextColor(rh.gac(context , R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.duration.currentTextColor)
|
if (abs(iob.basaliob) > 0.01) holder.binding.iob.setTextColor(rh.gac(context , R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.duration.currentTextColor)
|
||||||
holder.binding.cbRemove.visibility = (tempBasal.isValid && removeActionMode != null).toVisibility()
|
holder.binding.cbRemove.visibility = (tempBasal.isValid && actionHelper.isRemoving).toVisibility()
|
||||||
if (removeActionMode != null) {
|
if (actionHelper.isRemoving) {
|
||||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||||
if (value) {
|
actionHelper.updateSelection(position, tempBasal, value)
|
||||||
selectedItems.put(position, tempBasal)
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(position)
|
|
||||||
}
|
}
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
holder.binding.root.setOnClickListener {
|
||||||
|
holder.binding.cbRemove.toggle()
|
||||||
|
actionHelper.updateSelection(position, tempBasal, holder.binding.cbRemove.isChecked)
|
||||||
}
|
}
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||||
}
|
}
|
||||||
val nextTimestamp = if (tempBasalList.size != position + 1) tempBasalList[position + 1].timestamp else 0L
|
val nextTimestamp = if (tempBasalList.size != position + 1) tempBasalList[position + 1].timestamp else 0L
|
||||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(tempBasal.timestamp, nextTimestamp).toVisibility()
|
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(tempBasal.timestamp, nextTimestamp).toVisibility()
|
||||||
|
@ -221,32 +227,38 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
this.menu = menu
|
||||||
inflater.inflate(R.menu.menu_treatments_temp_basal, menu)
|
inflater.inflate(R.menu.menu_treatments_temp_basal, menu)
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateMenuVisibility() {
|
||||||
|
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||||
|
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
updateMenuVisibility()
|
||||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
|
||||||
|
|
||||||
return super.onPrepareOptionsMenu(menu)
|
return super.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.nav_remove_items -> {
|
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.nav_show_invalidated -> {
|
R.id.nav_show_invalidated -> {
|
||||||
showInvalidated = true
|
showInvalidated = true
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_hide_invalidated -> {
|
R.id.nav_hide_invalidated -> {
|
||||||
showInvalidated = false
|
showInvalidated = false
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -254,36 +266,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
private fun getConfirmationText(selectedItems: SparseArray<TemporaryBasal>): String {
|
||||||
|
|
||||||
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 {
|
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
val tempBasal = selectedItems.valueAt(0)
|
val tempBasal = selectedItems.valueAt(0)
|
||||||
val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED
|
val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED
|
||||||
|
@ -295,10 +278,10 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<TemporaryBasal>) {
|
||||||
if (selectedItems.size() > 0)
|
if (selectedItems.size() > 0)
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach {_, tempBasal ->
|
selectedItems.forEach {_, tempBasal ->
|
||||||
var extendedBolus: ExtendedBolus? = null
|
var extendedBolus: ExtendedBolus? = null
|
||||||
val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED
|
val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED
|
||||||
|
@ -331,10 +314,8 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
||||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) })
|
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,20 +13,21 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsUserEntryFragmentBinding
|
import info.nightscout.androidaps.databinding.TreatmentsUserEntryFragmentBinding
|
||||||
import info.nightscout.androidaps.databinding.TreatmentsUserEntryItemBinding
|
import info.nightscout.androidaps.databinding.TreatmentsUserEntryItemBinding
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
|
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||||
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.Translator
|
import info.nightscout.androidaps.utils.Translator
|
||||||
import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper
|
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
|
import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -47,9 +48,9 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
||||||
@Inject lateinit var userEntryPresentationHelper: UserEntryPresentationHelper
|
@Inject lateinit var userEntryPresentationHelper: UserEntryPresentationHelper
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
private val millsToThePastFiltered = T.days(30).msecs()
|
private val millsToThePastFiltered = T.days(30).msecs()
|
||||||
private val millsToThePastUnFiltered = T.days(3).msecs()
|
private val millsToThePastUnFiltered = T.days(3).msecs()
|
||||||
|
private var menu: Menu? = null
|
||||||
private var showLoop = false
|
private var showLoop = false
|
||||||
private var _binding: TreatmentsUserEntryFragmentBinding? = null
|
private var _binding: TreatmentsUserEntryFragmentBinding? = null
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exportUserEnteries() {
|
private fun exportUserEntries() {
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.ue_export_to_csv) + "?") {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.ue_export_to_csv) + "?") {
|
||||||
uel.log(Action.EXPORT_CSV, Sources.Treatments)
|
uel.log(Action.EXPORT_CSV, Sources.Treatments)
|
||||||
|
@ -94,7 +95,6 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
swapAdapter()
|
swapAdapter()
|
||||||
|
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventPreferenceChange::class.java)
|
.toObservable(EventPreferenceChange::class.java)
|
||||||
.observeOn(aapsSchedulers.io)
|
.observeOn(aapsSchedulers.io)
|
||||||
|
@ -134,11 +134,10 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
||||||
holder.binding.time.text = dateUtil.timeStringWithSeconds(current.timestamp)
|
holder.binding.time.text = dateUtil.timeStringWithSeconds(current.timestamp)
|
||||||
holder.binding.action.text = userEntryPresentationHelper.actionToColoredString(current.action)
|
holder.binding.action.text = userEntryPresentationHelper.actionToColoredString(current.action)
|
||||||
holder.binding.notes.text = current.note
|
holder.binding.notes.text = current.note
|
||||||
holder.binding.notes.visibility = if (current.note != "") View.VISIBLE else View.GONE
|
holder.binding.notes.visibility = (current.note != "").toVisibility()
|
||||||
holder.binding.iconSource.setImageResource(userEntryPresentationHelper.iconId(current.source))
|
holder.binding.iconSource.setImageResource(userEntryPresentationHelper.iconId(current.source))
|
||||||
holder.binding.iconSource.visibility = View.VISIBLE
|
|
||||||
holder.binding.values.text = userEntryPresentationHelper.listToPresentationString(current.values)
|
holder.binding.values.text = userEntryPresentationHelper.listToPresentationString(current.values)
|
||||||
holder.binding.values.visibility = if (holder.binding.values.text != "") View.VISIBLE else View.GONE
|
holder.binding.values.visibility = (holder.binding.values.text != "").toVisibility()
|
||||||
val nextTimestamp = if (entries.size != position + 1) entries[position + 1].timestamp else 0L
|
val nextTimestamp = if (entries.size != position + 1) entries[position + 1].timestamp else 0L
|
||||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(current.timestamp, nextTimestamp).toVisibility()
|
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(current.timestamp, nextTimestamp).toVisibility()
|
||||||
}
|
}
|
||||||
|
@ -152,14 +151,18 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
this.menu = menu
|
||||||
inflater.inflate(R.menu.menu_treatments_user_entry, menu)
|
inflater.inflate(R.menu.menu_treatments_user_entry, menu)
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
private fun updateMenuVisibility() {
|
||||||
menu.findItem(R.id.nav_hide_loop)?.isVisible = showLoop
|
menu?.findItem(R.id.nav_hide_loop)?.isVisible = showLoop
|
||||||
menu.findItem(R.id.nav_show_loop)?.isVisible = !showLoop
|
menu?.findItem(R.id.nav_show_loop)?.isVisible = !showLoop
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
|
updateMenuVisibility()
|
||||||
return super.onPrepareOptionsMenu(menu)
|
return super.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,21 +170,26 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.nav_show_loop -> {
|
R.id.nav_show_loop -> {
|
||||||
showLoop = true
|
showLoop = true
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_loop_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_hide_loop -> {
|
R.id.nav_hide_loop -> {
|
||||||
showLoop = false
|
showLoop = false
|
||||||
|
updateMenuVisibility()
|
||||||
|
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_hide_records))
|
||||||
rxBus.send(EventTreatmentUpdateGui())
|
rxBus.send(EventTreatmentUpdateGui())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_export -> {
|
R.id.nav_export -> {
|
||||||
exportUserEnteries()
|
exportUserEntries()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,6 @@ import android.view.*
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
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.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import info.nightscout.androidaps.R
|
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.databinding.OverviewQuickwizardlistItemBinding
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
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.dialogs.EditQuickWizardDialog
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
|
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
|
||||||
|
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
|
@ -33,7 +32,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
class QuickWizardListActivity : DaggerAppCompatActivityWithResult(), OnStartDragListener {
|
||||||
|
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
@Inject lateinit var rxBus: RxBus
|
@Inject lateinit var rxBus: RxBus
|
||||||
|
@ -43,49 +42,15 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||||
@Inject lateinit var sp: SP
|
@Inject lateinit var sp: SP
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
private var selectedItems: SparseArray<QuickWizardEntry> = SparseArray()
|
private lateinit var actionHelper: ActionModeHelper<QuickWizardEntry>
|
||||||
private var removeActionMode: ActionMode? = null
|
private val itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback())
|
||||||
private var sortActionMode: ActionMode? = null
|
|
||||||
|
|
||||||
private lateinit var binding: OverviewQuickwizardlistActivityBinding
|
private lateinit var binding: OverviewQuickwizardlistActivityBinding
|
||||||
|
|
||||||
private val itemTouchHelper by lazy {
|
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
|
||||||
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) {
|
|
||||||
itemTouchHelper.startDrag(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)
|
private inner class QuickWizardEntryViewHolder(val binding: OverviewQuickwizardlistItemBinding, val fragmentManager: FragmentManager) : RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
@ -112,61 +77,43 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
holder.binding.root.setOnClickListener {
|
||||||
if (sortActionMode != null && removeActionMode != null) {
|
if (actionHelper.isNoAction) {
|
||||||
holder.binding.cardview.setOnClickListener {
|
|
||||||
val manager = fragmentManager
|
val manager = fragmentManager
|
||||||
val editQuickWizardDialog = EditQuickWizardDialog()
|
val editQuickWizardDialog = EditQuickWizardDialog()
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putInt("position", position)
|
bundle.putInt("position", position)
|
||||||
editQuickWizardDialog.arguments = bundle
|
editQuickWizardDialog.arguments = bundle
|
||||||
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
||||||
}
|
} else if (actionHelper.isRemoving) {
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
holder.binding.cbRemove.toggle()
|
||||||
updateSelection(holder.binding.cbRemove.isChecked)
|
actionHelper.updateSelection(position, entry, holder.binding.cbRemove.isChecked)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
holder.binding.sortHandle.setOnTouchListener { _, event ->
|
||||||
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||||
|
onStartDrag(holder)
|
||||||
return@setOnTouchListener true
|
return@setOnTouchListener true
|
||||||
}
|
}
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
return@setOnTouchListener false
|
||||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value -> updateSelection(value) }
|
}
|
||||||
holder.binding.handleView.visibility = (sortActionMode != null).toVisibility()
|
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||||
holder.binding.cbRemove.visibility = (removeActionMode != null).toVisibility()
|
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
actionHelper.updateSelection(position, entry, value)
|
||||||
|
}
|
||||||
|
holder.binding.sortHandle.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) {
|
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
|
||||||
quickWizard.move(from, to)
|
binding.recyclerview.adapter?.notifyItemMoved(fromPosition, toPosition)
|
||||||
|
quickWizard.move(fromPosition, toPosition)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDrop() {
|
override fun onDrop() = rxBus.send(EventQuickWizardChange())
|
||||||
rxBus.send(EventQuickWizardChange())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -174,6 +121,11 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||||
binding = OverviewQuickwizardlistActivityBinding.inflate(layoutInflater)
|
binding = OverviewQuickwizardlistActivityBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
actionHelper = ActionModeHelper(rh, this)
|
||||||
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
|
actionHelper.enableSort = true
|
||||||
|
|
||||||
title = rh.gs(R.string.quickwizard)
|
title = rh.gs(R.string.quickwizard)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
@ -184,6 +136,7 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||||
itemTouchHelper.attachToRecyclerView(binding.recyclerview)
|
itemTouchHelper.attachToRecyclerView(binding.recyclerview)
|
||||||
|
|
||||||
binding.addButton.setOnClickListener {
|
binding.addButton.setOnClickListener {
|
||||||
|
actionHelper.finish()
|
||||||
val manager = supportFragmentManager
|
val manager = supportFragmentManager
|
||||||
val editQuickWizardDialog = EditQuickWizardDialog()
|
val editQuickWizardDialog = EditQuickWizardDialog()
|
||||||
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
||||||
|
@ -203,25 +156,22 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
|
actionHelper.finish()
|
||||||
super.onPause()
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<QuickWizardEntry>) {
|
||||||
if (selectedItems.size() > 0)
|
OKDialog.showConfirmation(this, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
OKDialog.showConfirmation(this, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
|
||||||
selectedItems.forEach { _, item ->
|
selectedItems.forEach { _, item ->
|
||||||
quickWizard.remove(item.position)
|
quickWizard.remove(item.position)
|
||||||
rxBus.send(EventQuickWizardChange())
|
rxBus.send(EventQuickWizardChange())
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
val inflater = menuInflater
|
menuInflater.inflate(R.menu.menu_actions, menu)
|
||||||
inflater.inflate(R.menu.menu_quickwizard, menu)
|
|
||||||
return super.onCreateOptionsMenu(menu)
|
return super.onCreateOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,76 +182,11 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_remove_items -> {
|
else -> actionHelper.onOptionsItemSelected(item)
|
||||||
removeActionMode = startActionMode(RemoveActionModeCallback())
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_sort_items -> {
|
private fun getConfirmationText(selectedItems: SparseArray<QuickWizardEntry>): String {
|
||||||
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) {
|
if (selectedItems.size() == 1) {
|
||||||
val entry = selectedItems.valueAt(0)
|
val entry = selectedItems.valueAt(0)
|
||||||
return "${rh.gs(R.string.remove_button)} ${entry.buttonText()} ${rh.gs(R.string.format_carbs, entry.carbs())}\n" +
|
return "${rh.gs(R.string.remove_button)} ${entry.buttonText()} ${rh.gs(R.string.format_carbs, entry.carbs())}\n" +
|
||||||
|
@ -309,4 +194,5 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||||
}
|
}
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
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.os.Bundle
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import androidx.core.util.forEach
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
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.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
@ -54,11 +54,9 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
|
|
||||||
private val disposable = CompositeDisposable()
|
private val disposable = CompositeDisposable()
|
||||||
private val millsToThePast = T.hours(36).msecs()
|
private val millsToThePast = T.hours(36).msecs()
|
||||||
private var selectedItems: SparseArray<GlucoseValue> = SparseArray()
|
private lateinit var actionHelper: ActionModeHelper<GlucoseValue>
|
||||||
private var toolbar: Toolbar? = null
|
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
|
|
||||||
private var _binding: BgsourceFragmentBinding? = null
|
private var _binding: BgsourceFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
@ -67,8 +65,10 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
toolbar = activity?.findViewById(R.id.toolbar)
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
setHasOptionsMenu(true)
|
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
|
setHasOptionsMenu(actionHelper.inMenu)
|
||||||
|
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
|
@ -97,44 +97,30 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
super.onPause()
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
inflater.inflate(R.menu.menu_bgsource, menu)
|
actionHelper.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
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)
|
super.onPrepareOptionsMenu(menu)
|
||||||
|
actionHelper.onPrepareOptionsMenu(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
binding.recyclerview.adapter = null // avoid leaks
|
binding.recyclerview.adapter = null // avoid leaks
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem) =
|
||||||
return when (item.itemId) {
|
actionHelper.onOptionsItemSelected(item)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class RecyclerViewAdapter internal constructor(private var glucoseValues: List<GlucoseValue>) : RecyclerView.Adapter<RecyclerViewAdapter.GlucoseValuesViewHolder>() {
|
inner class RecyclerViewAdapter internal constructor(private var glucoseValues: List<GlucoseValue>) : RecyclerView.Adapter<RecyclerViewAdapter.GlucoseValuesViewHolder>() {
|
||||||
|
|
||||||
|
@ -159,34 +145,29 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
if (diff < T.secs(20).msecs())
|
if (diff < T.secs(20).msecs())
|
||||||
holder.binding.root.setBackgroundColor(rh.gc(R.color.errorAlertBackground))
|
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 {
|
holder.binding.root.setOnLongClickListener {
|
||||||
if (removeActionMode == null) {
|
if (actionHelper.startRemove()) {
|
||||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
|
||||||
}
|
|
||||||
holder.binding.cbRemove.toggle()
|
holder.binding.cbRemove.toggle()
|
||||||
updateSelection(holder.binding.cbRemove.isChecked)
|
actionHelper.updateSelection(position, glucoseValue, holder.binding.cbRemove.isChecked)
|
||||||
true
|
return@setOnLongClickListener true
|
||||||
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
holder.binding.root.setOnClickListener {
|
holder.binding.root.setOnClickListener {
|
||||||
if (removeActionMode != null) {
|
if (actionHelper.isRemoving) {
|
||||||
holder.binding.cbRemove.toggle()
|
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.setOnCheckedChangeListener { _, value ->
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
actionHelper.updateSelection(position, glucoseValue, value)
|
||||||
holder.binding.cbRemove.visibility = (removeActionMode != null).toVisibility()
|
}
|
||||||
|
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) {
|
inner class GlucoseValuesViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
|
@ -194,36 +175,7 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
private fun getConfirmationText(selectedItems: SparseArray<GlucoseValue>): String {
|
||||||
|
|
||||||
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 {
|
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
val glucoseValue = selectedItems.valueAt(0)
|
val glucoseValue = selectedItems.valueAt(0)
|
||||||
return dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits())
|
return dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits())
|
||||||
|
@ -231,10 +183,9 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<GlucoseValue>) {
|
||||||
if (selectedItems.size() > 0)
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach { _, glucoseValue ->
|
selectedItems.forEach { _, glucoseValue ->
|
||||||
val source = when ((activePlugin.activeBgSource as PluginBase).pluginDescription.pluginName) {
|
val source = when ((activePlugin.activeBgSource as PluginBase).pluginDescription.pluginName) {
|
||||||
R.string.dexcom_app_patched -> Sources.Dexcom
|
R.string.dexcom_app_patched -> Sources.Dexcom
|
||||||
|
@ -257,10 +208,8 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
.blockingGet()
|
.blockingGet()
|
||||||
.also { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bg $it") } }
|
.also { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bg $it") } }
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24"
|
||||||
android:viewportWidth="24">
|
android:viewportWidth="24">
|
||||||
<path
|
<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"/>
|
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>
|
</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>
|
|
@ -5,8 +5,8 @@
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:pathData="M12,4.531c-4.971,0 -9.209,3.1 -10.912,7.469C2.791,16.368 7.029,19.469 12,19.469s9.209,-3.1 10.912,-7.469C21.209,7.632 16.971,4.531 12,4.531zM12,17.063c-2.796,0 -5.063,-2.267 -5.063,-5.063S9.204,6.938 12,6.938S17.063,9.204 17.063,12S14.796,17.063 12,17.063z"
|
android:pathData="M12,4.531c-4.971,0 -9.209,3.1 -10.912,7.469C2.791,16.368 7.029,19.469 12,19.469s9.209,-3.1 10.912,-7.469C21.209,7.632 16.971,4.531 12,4.531zM12,17.063c-2.796,0 -5.063,-2.267 -5.063,-5.063S9.204,6.938 12,6.938S17.063,9.204 17.063,12S14.796,17.063 12,17.063z"
|
||||||
android:fillColor="#FFFFFF"/>
|
android:fillColor="?attr/colorControlNormal"/>
|
||||||
<path
|
<path
|
||||||
android:pathData="M12,12m-2.938,0a2.938,2.938 0,1 1,5.876 0a2.938,2.938 0,1 1,-5.876 0"
|
android:pathData="M12,12m-2.938,0a2.938,2.938 0,1 1,5.876 0a2.938,2.938 0,1 1,-5.876 0"
|
||||||
android:fillColor="#FFFFFF"/>
|
android:fillColor="?attr/colorControlNormal"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
9
app/src/main/res/drawable/ic_visibility_off.xml
Normal file
9
app/src/main/res/drawable/ic_visibility_off.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<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="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z" />
|
||||||
|
</vector>
|
|
@ -81,7 +81,7 @@
|
||||||
tools:ignore="RtlSymmetry" />
|
tools:ignore="RtlSymmetry" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/handleView"
|
android:id="@+id/sortHandle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:adjustViewBounds="false"
|
android:adjustViewBounds="false"
|
||||||
|
|
|
@ -165,8 +165,9 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/cb_bolus_remove"
|
android:id="@+id/cb_bolus_remove"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="19dp"
|
||||||
android:contentDescription="@string/select_for_removal"
|
android:contentDescription="@string/select_for_removal"
|
||||||
|
android:minWidth="0dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -254,22 +255,13 @@
|
||||||
android:text="@string/invalid"
|
android:text="@string/invalid"
|
||||||
android:textColor="@android:color/holo_red_light" />
|
android:textColor="@android:color/holo_red_light" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/carbs_remove"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
|
|
||||||
android:text="@string/remove_button"
|
|
||||||
android:textAlignment="viewEnd"
|
|
||||||
android:textColor="@android:color/holo_orange_light" />
|
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/cb_carbs_remove"
|
android:id="@+id/cb_carbs_remove"
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="19dp"
|
||||||
|
android:contentDescription="@string/select_for_removal"
|
||||||
|
android:minWidth="0dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -115,8 +115,9 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/cb_remove"
|
android:id="@+id/cb_remove"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="19dp"
|
||||||
android:contentDescription="@string/select_for_removal"
|
android:contentDescription="@string/select_for_removal"
|
||||||
|
android:minWidth="0dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -156,8 +156,9 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/cb_remove"
|
android:id="@+id/cb_remove"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="19dp"
|
||||||
android:contentDescription="@string/select_for_removal"
|
android:contentDescription="@string/select_for_removal"
|
||||||
|
android:minWidth="0dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -127,8 +127,9 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/cb_remove"
|
android:id="@+id/cb_remove"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="19dp"
|
||||||
android:contentDescription="@string/select_for_removal"
|
android:contentDescription="@string/select_for_removal"
|
||||||
|
android:minWidth="0dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -175,8 +175,9 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/cb_remove"
|
android:id="@+id/cb_remove"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="19dp"
|
||||||
android:contentDescription="@string/select_for_removal"
|
android:contentDescription="@string/select_for_removal"
|
||||||
|
android:minWidth="0dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
@ -150,8 +150,9 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/cb_remove"
|
android:id="@+id/cb_remove"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="19dp"
|
||||||
android:contentDescription="@string/select_for_removal"
|
android:contentDescription="@string/select_for_removal"
|
||||||
|
android:minWidth="0dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -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
|
<item
|
||||||
android:id="@+id/remove_selected"
|
android:id="@+id/remove_selected"
|
||||||
android:icon="@drawable/ic_trash"
|
android:icon="@drawable/ic_trash"
|
||||||
android:iconTint="?attr/trashBinTintColor"
|
android:iconTint="?attr/colorControlNormal"
|
||||||
android:title="@string/remove_selected_items"
|
android:title="@string/remove_selected_items"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
tools:context=".MainActivity">
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_plugin_preferences"
|
android:id="@+id/nav_plugin_preferences"
|
||||||
|
android:orderInCategory="1"
|
||||||
app:showAsAction="ifRoom"
|
app:showAsAction="ifRoom"
|
||||||
android:icon="@drawable/ic_settings"
|
android:icon="@drawable/ic_settings"
|
||||||
android:title="@string/nav_plugin_preferences" />
|
android:title="@string/nav_plugin_preferences" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -3,20 +3,27 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_items"
|
android:id="@+id/nav_remove_items"
|
||||||
|
android:icon="@drawable/ic_trash"
|
||||||
android:title="@string/remove_items"
|
android:title="@string/remove_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_show_invalidated"
|
android:id="@+id/nav_show_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility"
|
||||||
android:title="@string/show_invalidated"
|
android:title="@string/show_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_hide_invalidated"
|
android:id="@+id/nav_hide_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility_off"
|
||||||
android:title="@string/hide_invalidated"
|
android:title="@string/hide_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_delete_future"
|
android:id="@+id/nav_delete_future"
|
||||||
android:title="@string/delete_future_treatments"
|
android:title="@string/delete_future_treatments"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_refresh_ns"
|
android:id="@+id/nav_refresh_ns"
|
||||||
android:title="@string/refresh_from_nightscout"
|
android:title="@string/refresh_from_nightscout"
|
||||||
|
|
|
@ -3,20 +3,27 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_items"
|
android:id="@+id/nav_remove_items"
|
||||||
|
android:icon="@drawable/ic_trash"
|
||||||
android:title="@string/remove_items"
|
android:title="@string/remove_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_show_invalidated"
|
android:id="@+id/nav_show_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility"
|
||||||
android:title="@string/show_invalidated"
|
android:title="@string/show_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_hide_invalidated"
|
android:id="@+id/nav_hide_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility_off"
|
||||||
android:title="@string/hide_invalidated"
|
android:title="@string/hide_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_refresh_ns"
|
android:id="@+id/nav_refresh_ns"
|
||||||
android:title="@string/refresh_from_nightscout"
|
android:title="@string/refresh_from_nightscout"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_started_events"
|
android:id="@+id/nav_remove_started_events"
|
||||||
android:title="@string/careportal_removestartedevents"
|
android:title="@string/careportal_removestartedevents"
|
||||||
|
|
|
@ -3,15 +3,20 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_items"
|
android:id="@+id/nav_remove_items"
|
||||||
|
android:icon="@drawable/ic_trash"
|
||||||
android:title="@string/remove_items"
|
android:title="@string/remove_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_show_invalidated"
|
android:id="@+id/nav_show_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility"
|
||||||
android:title="@string/show_invalidated"
|
android:title="@string/show_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_hide_invalidated"
|
android:id="@+id/nav_hide_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility_off"
|
||||||
android:title="@string/hide_invalidated"
|
android:title="@string/hide_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -3,15 +3,20 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_items"
|
android:id="@+id/nav_remove_items"
|
||||||
|
android:icon="@drawable/ic_trash"
|
||||||
android:title="@string/remove_items"
|
android:title="@string/remove_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_show_invalidated"
|
android:id="@+id/nav_show_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility"
|
||||||
android:title="@string/show_invalidated"
|
android:title="@string/show_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_hide_invalidated"
|
android:id="@+id/nav_hide_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility_off"
|
||||||
android:title="@string/hide_invalidated"
|
android:title="@string/hide_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -3,15 +3,20 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_items"
|
android:id="@+id/nav_remove_items"
|
||||||
|
android:icon="@drawable/ic_trash"
|
||||||
android:title="@string/remove_items"
|
android:title="@string/remove_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_show_invalidated"
|
android:id="@+id/nav_show_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility"
|
||||||
android:title="@string/show_invalidated"
|
android:title="@string/show_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_hide_invalidated"
|
android:id="@+id/nav_hide_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility_off"
|
||||||
android:title="@string/hide_invalidated"
|
android:title="@string/hide_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -3,16 +3,22 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_items"
|
android:id="@+id/nav_remove_items"
|
||||||
|
android:icon="@drawable/ic_trash"
|
||||||
android:title="@string/remove_items"
|
android:title="@string/remove_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_show_invalidated"
|
android:id="@+id/nav_show_invalidated"
|
||||||
|
android:icon="@drawable/ic_visibility"
|
||||||
android:title="@string/show_invalidated"
|
android:title="@string/show_invalidated"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_hide_invalidated"
|
android:id="@+id/nav_hide_invalidated"
|
||||||
android:title="@string/hide_invalidated"
|
android:title="@string/hide_invalidated"
|
||||||
app:showAsAction="never" />
|
android:icon="@drawable/ic_visibility_off"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_refresh_ns"
|
android:id="@+id/nav_refresh_ns"
|
||||||
android:title="@string/refresh_from_nightscout"
|
android:title="@string/refresh_from_nightscout"
|
||||||
|
|
|
@ -3,12 +3,17 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_show_loop"
|
android:id="@+id/nav_show_loop"
|
||||||
|
android:icon="@drawable/ic_loop_closed_white"
|
||||||
|
android:iconTint="?attr/colorControlNormal"
|
||||||
android:title="@string/show_loop"
|
android:title="@string/show_loop"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_hide_loop"
|
android:id="@+id/nav_hide_loop"
|
||||||
|
android:icon="@drawable/ic_loop_closed_off"
|
||||||
android:title="@string/hide_loop"
|
android:title="@string/hide_loop"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_export"
|
android:id="@+id/nav_export"
|
||||||
android:title="@string/ue_export_to_csv"
|
android:title="@string/ue_export_to_csv"
|
||||||
|
|
|
@ -1188,6 +1188,8 @@
|
||||||
<string name="wear_unknown_action_string">Unknown action command:</string>
|
<string name="wear_unknown_action_string">Unknown action command:</string>
|
||||||
<string name="overview_editquickwizard_percentage">Percentage</string>
|
<string name="overview_editquickwizard_percentage">Percentage</string>
|
||||||
<string name="app_default">Application default</string>
|
<string name="app_default">Application default</string>
|
||||||
|
<string name="show_invalidated_records">Show invalidated / removed records</string>
|
||||||
|
<string name="hide_invalidated_records">Hide invalidated / removed records</string>
|
||||||
<string name="select_profile">Select profile to edit</string>
|
<string name="select_profile">Select profile to edit</string>
|
||||||
<string name="refresh_from_nightscout">Refresh from Nightscout</string>
|
<string name="refresh_from_nightscout">Refresh from Nightscout</string>
|
||||||
<string name="remove_selected_items">Remove selected items</string>
|
<string name="remove_selected_items">Remove selected items</string>
|
||||||
|
@ -1204,4 +1206,6 @@
|
||||||
<string name="below" comment="below "in range"">Below</string>
|
<string name="below" comment="below "in range"">Below</string>
|
||||||
<string name="in_range">In range</string>
|
<string name="in_range">In range</string>
|
||||||
<string name="above" comment="above "in range"">Above</string>
|
<string name="above" comment="above "in range"">Above</string>
|
||||||
|
<string name="show_loop_records">Show loop records</string>
|
||||||
|
<string name="show_hide_records">Hide loop records</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -6,10 +6,10 @@ import android.os.Bundle
|
||||||
import android.text.method.ScrollingMovementMethod
|
import android.text.method.ScrollingMovementMethod
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.core.util.forEach
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.core.util.forEach
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -20,24 +20,24 @@ import info.nightscout.androidaps.automation.databinding.AutomationEventItemBind
|
||||||
import info.nightscout.androidaps.automation.databinding.AutomationFragmentBinding
|
import info.nightscout.androidaps.automation.databinding.AutomationFragmentBinding
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||||
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
||||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
|
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.events.EventAutomationUpdateGui
|
||||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
||||||
|
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import info.nightscout.androidaps.utils.dragHelpers.ItemTouchHelperAdapter
|
||||||
import info.nightscout.androidaps.extensions.toVisibility
|
import info.nightscout.androidaps.utils.dragHelpers.OnStartDragListener
|
||||||
import info.nightscout.androidaps.plugins.general.automation.dragHelpers.ItemTouchHelperAdapter
|
import info.nightscout.androidaps.utils.dragHelpers.SimpleItemTouchHelperCallback
|
||||||
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.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import java.util.*
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
|
@ -52,11 +52,8 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
private lateinit var eventListAdapter: EventListAdapter
|
private lateinit var eventListAdapter: EventListAdapter
|
||||||
private var selectedItems: SparseArray<AutomationEvent> = SparseArray()
|
private lateinit var actionHelper: ActionModeHelper<AutomationEvent>
|
||||||
private var removeActionMode: ActionMode? = null
|
|
||||||
private var sortActionMode: ActionMode? = null
|
|
||||||
private val itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback())
|
private val itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback())
|
||||||
|
|
||||||
private var _binding: AutomationFragmentBinding? = null
|
private var _binding: AutomationFragmentBinding? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and onDestroyView.
|
// This property is only valid between onCreateView and onDestroyView.
|
||||||
|
@ -64,20 +61,22 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
_binding = AutomationFragmentBinding.inflate(inflater, container, false)
|
_binding = AutomationFragmentBinding.inflate(inflater, container, false)
|
||||||
|
actionHelper = ActionModeHelper(rh, activity)
|
||||||
|
actionHelper.setUpdateListHandler { binding.eventListView.adapter?.notifyDataSetChanged() }
|
||||||
|
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||||
|
actionHelper.enableSort = true
|
||||||
|
setHasOptionsMenu(actionHelper.inMenu)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setHasOptionsMenu(true)
|
|
||||||
|
|
||||||
eventListAdapter = EventListAdapter()
|
eventListAdapter = EventListAdapter()
|
||||||
binding.eventListView.layoutManager = LinearLayoutManager(context)
|
binding.eventListView.layoutManager = LinearLayoutManager(context)
|
||||||
binding.eventListView.adapter = eventListAdapter
|
binding.eventListView.adapter = eventListAdapter
|
||||||
binding.logView.movementMethod = ScrollingMovementMethod()
|
binding.logView.movementMethod = ScrollingMovementMethod()
|
||||||
binding.fabAddEvent.setOnClickListener {
|
binding.fabAddEvent.setOnClickListener {
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
sortActionMode?.finish()
|
|
||||||
val dialog = EditEventDialog()
|
val dialog = EditEventDialog()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putString("event", AutomationEvent(injector).toJSON())
|
args.putString("event", AutomationEvent(injector).toJSON())
|
||||||
|
@ -110,8 +109,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
sortActionMode?.finish()
|
|
||||||
super.onPause()
|
super.onPause()
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
@ -119,38 +117,16 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
removeActionMode?.finish()
|
|
||||||
sortActionMode?.finish()
|
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
inflater.inflate(R.menu.menu_automation, menu)
|
actionHelper.onCreateOptionsMenu(menu, inflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||||
// Only show when tab automation is shown
|
actionHelper.onOptionsItemSelected(item)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
private fun updateGui() {
|
private fun updateGui() {
|
||||||
|
@ -228,59 +204,54 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
for (res in actionIcons) {
|
for (res in actionIcons) {
|
||||||
addImage(res, holder.context, holder.binding.iconLayout)
|
addImage(res, holder.context, holder.binding.iconLayout)
|
||||||
}
|
}
|
||||||
// enabled event
|
holder.binding.aapsLogo.visibility = (automation.systemAction).toVisibility()
|
||||||
|
// Enabled events
|
||||||
holder.binding.enabled.setOnClickListener {
|
holder.binding.enabled.setOnClickListener {
|
||||||
automation.isEnabled = holder.binding.enabled.isChecked
|
automation.isEnabled = holder.binding.enabled.isChecked
|
||||||
rxBus.send(EventAutomationDataChanged())
|
rxBus.send(EventAutomationDataChanged())
|
||||||
}
|
}
|
||||||
holder.binding.aapsLogo.visibility = (automation.systemAction).toVisibility()
|
holder.binding.rootLayout.setOnClickListener {
|
||||||
|
if (actionHelper.isNoAction) {
|
||||||
fun updateSelection(selected: Boolean) {
|
|
||||||
if (selected) {
|
|
||||||
selectedItems.put(position, automation)
|
|
||||||
} else {
|
|
||||||
selectedItems.remove(position)
|
|
||||||
}
|
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.binding.rootLayout.setOnTouchListener { _, touchEvent ->
|
|
||||||
if (touchEvent.actionMasked == MotionEvent.ACTION_UP && sortActionMode == null && removeActionMode == null) {
|
|
||||||
val dialog = EditEventDialog()
|
val dialog = EditEventDialog()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putString("event", automation.toJSON())
|
args.putString("event", automation.toJSON())
|
||||||
args.putInt("position", position)
|
args.putInt("position", position)
|
||||||
dialog.arguments = args
|
dialog.arguments = args
|
||||||
dialog.show(childFragmentManager, "EditEventDialog")
|
dialog.show(childFragmentManager, "EditEventDialog")
|
||||||
}
|
} else if (actionHelper.isRemoving) {
|
||||||
if (touchEvent.actionMasked == MotionEvent.ACTION_DOWN && sortActionMode != null) {
|
|
||||||
onStartDrag(holder)
|
|
||||||
}
|
|
||||||
if (touchEvent.actionMasked == MotionEvent.ACTION_UP && removeActionMode != null) {
|
|
||||||
holder.binding.cbRemove.toggle()
|
holder.binding.cbRemove.toggle()
|
||||||
updateSelection(holder.binding.cbRemove.isChecked)
|
actionHelper.updateSelection(position, automation, holder.binding.cbRemove.isChecked)
|
||||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
holder.binding.rootLayout.setOnLongClickListener {
|
||||||
|
actionHelper.startAction()
|
||||||
|
}
|
||||||
|
holder.binding.sortHandle.setOnTouchListener { _, touchEvent ->
|
||||||
|
if (touchEvent.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||||
|
onStartDrag(holder)
|
||||||
return@setOnTouchListener true
|
return@setOnTouchListener true
|
||||||
}
|
}
|
||||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
return@setOnTouchListener false
|
||||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value -> updateSelection(value) }
|
}
|
||||||
holder.binding.iconSort.visibility = (sortActionMode != null).toVisibility()
|
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||||
holder.binding.cbRemove.visibility = (removeActionMode != null).toVisibility()
|
actionHelper.updateSelection(position, automation, value)
|
||||||
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.sortHandle.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 {
|
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
|
||||||
|
binding.eventListView.adapter?.notifyItemMoved(fromPosition, toPosition)
|
||||||
automationPlugin.swap(fromPosition, toPosition)
|
automationPlugin.swap(fromPosition, toPosition)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDrop() {
|
override fun onDrop() = rxBus.send(EventAutomationDataChanged())
|
||||||
rxBus.send(EventAutomationDataChanged())
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class ViewHolder(view: View, val context: Context) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View, val context: Context) : RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
|
@ -288,54 +259,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class SortActionModeCallback : ActionMode.Callback {
|
private fun getConfirmationText(selectedItems: SparseArray<AutomationEvent>): String {
|
||||||
|
|
||||||
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 {
|
|
||||||
if (selectedItems.size() == 1) {
|
if (selectedItems.size() == 1) {
|
||||||
val event = selectedItems.valueAt(0)
|
val event = selectedItems.valueAt(0)
|
||||||
return rh.gs(R.string.removerecord) + " " + event.title
|
return rh.gs(R.string.removerecord) + " " + event.title
|
||||||
|
@ -343,20 +267,17 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
|
||||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeSelected() {
|
private fun removeSelected(selectedItems: SparseArray<AutomationEvent>) {
|
||||||
if (selectedItems.size() > 0) {
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||||
selectedItems.forEach { _, event ->
|
selectedItems.forEach { _, event ->
|
||||||
uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, event.title)
|
uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, event.title)
|
||||||
automationPlugin.removeAt(event.position)
|
automationPlugin.removeAt(event.position)
|
||||||
rxBus.send(EventAutomationDataChanged())
|
rxBus.send(EventAutomationDataChanged())
|
||||||
}
|
}
|
||||||
removeActionMode?.finish()
|
actionHelper.finish()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
removeActionMode?.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,12 +55,12 @@
|
||||||
android:contentDescription="@string/remove_label"
|
android:contentDescription="@string/remove_label"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/iconLayout"
|
app:layout_constraintBottom_toTopOf="@+id/iconLayout"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/iconSort"
|
app:layout_constraintEnd_toStartOf="@+id/sortHandle"
|
||||||
app:layout_constraintStart_toEndOf="@+id/eventTitle"
|
app:layout_constraintStart_toEndOf="@+id/eventTitle"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/iconSort"
|
android:id="@+id/sortHandle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
|
|
|
@ -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,191 @@
|
||||||
|
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 ActionModeHelper<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(): Boolean {
|
||||||
|
if (isNoAction) {
|
||||||
|
actionMode = activity?.startActionMode(ActionModeCallback())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startRemove(): Boolean {
|
||||||
|
if (removeActionMode == null) {
|
||||||
|
removeActionMode = activity?.startActionMode(RemoveActionModeCallback())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startSort(): Boolean {
|
||||||
|
if (sortActionMode == null) {
|
||||||
|
sortActionMode = activity?.startActionMode(SortActionModeCallback())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.dragHelpers
|
package info.nightscout.androidaps.utils.dragHelpers
|
||||||
|
|
||||||
interface ItemTouchHelperAdapter {
|
interface ItemTouchHelperAdapter {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.dragHelpers
|
package info.nightscout.androidaps.utils.dragHelpers
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.dragHelpers
|
package info.nightscout.androidaps.utils.dragHelpers
|
||||||
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
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.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import info.nightscout.androidaps.plugins.general.automation.AutomationFragment
|
|
||||||
|
|
||||||
class SimpleItemTouchHelperCallback : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.START or ItemTouchHelper.END, 0) {
|
const val ALPHA_FULL = 1f
|
||||||
|
const val ALPHA_DRAGGING = 0.5f
|
||||||
|
|
||||||
override fun isLongPressDragEnabled(): Boolean {
|
class SimpleItemTouchHelperCallback : ItemTouchHelper.SimpleCallback(UP or DOWN or START or END, 0) {
|
||||||
return false
|
|
||||||
}
|
override fun isLongPressDragEnabled() = false
|
||||||
|
|
||||||
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 AutomationFragment.EventListAdapter
|
val adapter = recyclerView.adapter as ItemTouchHelperAdapter
|
||||||
val from = viewHolder.layoutPosition
|
val from = viewHolder.layoutPosition
|
||||||
val to = target.layoutPosition
|
val to = target.layoutPosition
|
||||||
adapter.onItemMove(from, to)
|
adapter.onItemMove(from, to)
|
||||||
adapter.notifyItemMoved(from, to)
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -24,14 +28,14 @@ class SimpleItemTouchHelperCallback : ItemTouchHelper.SimpleCallback(ItemTouchHe
|
||||||
|
|
||||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||||
super.onSelectedChanged(viewHolder, actionState)
|
super.onSelectedChanged(viewHolder, actionState)
|
||||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
if (actionState == ACTION_STATE_DRAG) {
|
||||||
viewHolder?.itemView?.alpha = 0.5f
|
viewHolder?.itemView?.alpha = ALPHA_DRAGGING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||||
super.clearView(recyclerView, viewHolder)
|
super.clearView(recyclerView, viewHolder)
|
||||||
viewHolder.itemView.alpha = 1.0f
|
viewHolder.itemView.alpha = ALPHA_FULL
|
||||||
(recyclerView.adapter as AutomationFragment.EventListAdapter).onDrop()
|
(recyclerView.adapter as ItemTouchHelperAdapter).onDrop()
|
||||||
}
|
}
|
||||||
}
|
}
|
15
core/src/main/res/drawable/ic_loop_closed_off.xml
Normal file
15
core/src/main/res/drawable/ic_loop_closed_off.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="48dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M19.255,18.907l-1.967,-1.967l0,0L6.801,6.453L5.218,4.87l0,0l-1.88,-1.88L2.041,4.286l1.971,1.971C2.829,7.89 2.125,9.891 2.125,12.063c0,5.488 4.449,9.938 9.938,9.938c2.171,0 4.172,-0.704 5.805,-1.887l1.91,1.91l1.296,-1.296L19.255,18.907L19.255,18.907zM12.063,19.219c-3.952,0 -7.156,-3.204 -7.156,-7.156c0,-1.401 0.412,-2.7 1.109,-3.802l9.849,9.849C14.763,18.807 13.463,19.219 12.063,19.219z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M12.063,4.906c1.072,0 2.085,0.242 2.998,0.665c0.325,0.151 0.639,0.321 0.936,0.517l0.002,-0.002l-0.352,-1.784l1.876,-0.538c-1.567,-1.033 -3.442,-1.639 -5.46,-1.639c-1.991,0 -3.842,0.592 -5.397,1.6l2.026,2.026C9.696,5.213 10.843,4.906 12.063,4.906z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M24,9.343l-5.781,-3.968l-1.328,6.688l2.102,-1.757c0.014,0.056 0.03,0.111 0.043,0.168c0.116,0.512 0.183,1.042 0.183,1.589c0,1.219 -0.307,2.366 -0.844,3.371l2.025,2.025c1.009,-1.555 1.6,-3.405 1.6,-5.397c0,-0.759 -0.093,-1.496 -0.254,-2.206c-0.04,-0.176 -0.085,-0.35 -0.134,-0.523L24,9.343L24,9.343z" />
|
||||||
|
</vector>
|
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>
|
|
@ -3,12 +3,17 @@
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_remove_items"
|
android:id="@+id/nav_remove_items"
|
||||||
|
android:icon="@drawable/ic_trash"
|
||||||
|
android:iconTint="?attr/colorControlNormal"
|
||||||
|
android:orderInCategory="0"
|
||||||
android:title="@string/remove_items"
|
android:title="@string/remove_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_sort_items"
|
android:id="@+id/nav_sort_items"
|
||||||
|
android:icon="@drawable/ic_sort"
|
||||||
|
android:orderInCategory="0"
|
||||||
android:title="@string/sort_items"
|
android:title="@string/sort_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
|
@ -4,8 +4,8 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/remove_selected"
|
android:id="@+id/remove_selected"
|
||||||
android:icon="@drawable/ic_trash"
|
android:icon="@drawable/ic_trash"
|
||||||
android:iconTint="@color/white"
|
android:iconTint="?attr/colorControlNormal"
|
||||||
android:title="@string/remove_selected_items"
|
android:title="@string/remove_selected_items"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
|
@ -556,6 +556,11 @@
|
||||||
<string name="formatPercent">%1$.0f%%</string>
|
<string name="formatPercent">%1$.0f%%</string>
|
||||||
<string name="basal">Basal</string>
|
<string name="basal">Basal</string>
|
||||||
<string name="basalpct">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">
|
<plurals name="days">
|
||||||
<item quantity="one">%1$d day</item>
|
<item quantity="one">%1$d day</item>
|
||||||
|
|
19
icons/loop_off.svg
Normal file
19
icons/loop_off.svg
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
|
||||||
|
height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||||
|
<g id="loop_x5F_Off">
|
||||||
|
<rect width="24" height="24"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M19.255,18.907l-1.967-1.967l0,0L6.801,6.453L5.218,4.87l0,0l-1.88-1.88L2.041,4.286l1.971,1.971
|
||||||
|
C2.829,7.89,2.125,9.891,2.125,12.063c0,5.488,4.449,9.938,9.938,9.938c2.171,0,4.172-0.704,5.805-1.887l1.91,1.91l1.296-1.296
|
||||||
|
L19.255,18.907L19.255,18.907z M12.063,19.219c-3.952,0-7.156-3.204-7.156-7.156c0-1.401,0.412-2.7,1.109-3.802l9.849,9.849
|
||||||
|
C14.763,18.807,13.463,19.219,12.063,19.219z"/>
|
||||||
|
<path fill="#FFFFFF" d="M12.063,4.906c1.072,0,2.085,0.242,2.998,0.665c0.325,0.151,0.639,0.321,0.936,0.517l0.002-0.002
|
||||||
|
l-0.352-1.784l1.876-0.538c-1.567-1.033-3.442-1.639-5.46-1.639c-1.991,0-3.842,0.592-5.397,1.6l2.026,2.026
|
||||||
|
C9.696,5.213,10.843,4.906,12.063,4.906z"/>
|
||||||
|
<path fill="#FFFFFF" d="M24,9.343l-5.781-3.968l-1.328,6.688l2.102-1.757c0.014,0.056,0.03,0.111,0.043,0.168
|
||||||
|
c0.116,0.512,0.183,1.042,0.183,1.589c0,1.219-0.307,2.366-0.844,3.371l2.025,2.025c1.009-1.555,1.6-3.405,1.6-5.397
|
||||||
|
c0-0.759-0.093-1.496-0.254-2.206c-0.04-0.176-0.085-0.35-0.134-0.523L24,9.343L24,9.343z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
Loading…
Reference in a new issue