diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt index f758398d62..b5266e4d3f 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt @@ -12,11 +12,6 @@ import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragm import info.nightscout.androidaps.plugins.constraints.objectives.activities.ObjectivesExamDialog import info.nightscout.androidaps.plugins.general.actions.ActionsFragment import info.nightscout.androidaps.plugins.general.automation.AutomationFragment -import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseActionDialog -import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog -import info.nightscout.androidaps.plugins.general.automation.dialogs.EditActionDialog -import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog -import info.nightscout.androidaps.plugins.general.automation.dialogs.EditTriggerDialog import info.nightscout.androidaps.plugins.general.food.FoodFragment import info.nightscout.androidaps.plugins.general.maintenance.MaintenanceFragment import info.nightscout.androidaps.plugins.general.nsclient.NSClientFragment @@ -30,6 +25,7 @@ import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment import info.nightscout.androidaps.plugins.source.BGSourceFragment import info.nightscout.androidaps.activities.fragments.* +import info.nightscout.androidaps.plugins.general.automation.dialogs.* import info.nightscout.androidaps.utils.protection.PasswordCheck @Module @@ -81,6 +77,7 @@ abstract class FragmentsModule { @ContributesAndroidInjector abstract fun contributesFillDialog(): FillDialog @ContributesAndroidInjector abstract fun contributesChooseActionDialog(): ChooseActionDialog @ContributesAndroidInjector abstract fun contributesChooseTriggerDialog(): ChooseTriggerDialog + @ContributesAndroidInjector abstract fun contributesChooseOperationDialog(): ChooseOperationDialog @ContributesAndroidInjector abstract fun contributesInsulinDialog(): InsulinDialog @ContributesAndroidInjector abstract fun contributesLoopDialog(): LoopDialog @ContributesAndroidInjector abstract fun contributesObjectivesExamDialog(): ObjectivesExamDialog diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index e856725742..36735b856a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -12,6 +12,7 @@ import android.os.Bundle import android.os.Handler import android.os.HandlerThread import android.util.DisplayMetrics +import android.util.TypedValue import android.view.LayoutInflater import android.view.View import android.view.View.OnLongClickListener @@ -49,6 +50,7 @@ import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverview @@ -72,6 +74,7 @@ import info.nightscout.androidaps.utils.protection.ProtectionCheck import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.sharedPreferences.SP +import info.nightscout.androidaps.utils.ui.SingleClickButton import info.nightscout.androidaps.utils.ui.UIRunnable import info.nightscout.androidaps.utils.wizard.QuickWizard import io.reactivex.disposables.CompositeDisposable @@ -118,6 +121,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider @Inject lateinit var overviewData: OverviewData @Inject lateinit var overviewPlugin: OverviewPlugin + @Inject lateinit var automationPlugin: AutomationPlugin private val disposable = CompositeDisposable() @@ -459,6 +463,32 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList binding.buttonsLayout.calibrationButton.visibility = ((xDripIsBgSource || dexcomIsSource) && actualBG != null && sp.getBoolean(R.string.key_show_calibration_button, true)).toVisibility() binding.buttonsLayout.cgmButton.visibility = (sp.getBoolean(R.string.key_show_cgm_button, false) && (xDripIsBgSource || dexcomIsSource)).toVisibility() + // Automation buttons + binding.buttonsLayout.userButtonsLayout.removeAllViews() + val events = automationPlugin.userEvents() + for (event in events) + if (event.isEnabled && event.trigger.shouldRun()) + context?.let { context -> + SingleClickButton(context).also { + it.setTextColor(resourceHelper.gc(R.color.colorTreatmentButton)) + it.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10f) + it.layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 0.5f).also { l -> + l.setMargins(0, 0, resourceHelper.dpToPx(-4), 0) + } + it.setCompoundDrawablesWithIntrinsicBounds(null, resourceHelper.gd(R.drawable.ic_danar_useropt), null, null) + it.text = event.title + + it.setOnClickListener { + OKDialog.showConfirmation( + context, + resourceHelper.gs(R.string.run_question, event.title), + { handler.post { automationPlugin.processEvent(event, true) } } + ) + } + binding.buttonsLayout.userButtonsLayout.addView(it) + } + } + binding.buttonsLayout.userButtonsLayout.visibility = events.isNotEmpty().toVisibility() } private fun processAps() { diff --git a/app/src/main/res/layout/overview_buttons_layout.xml b/app/src/main/res/layout/overview_buttons_layout.xml index 29eba5f007..c8c761c3d2 100644 --- a/app/src/main/res/layout/overview_buttons_layout.xml +++ b/app/src/main/res/layout/overview_buttons_layout.xml @@ -18,6 +18,16 @@ android:textColor="@color/colorAcceptTempButton" android:visibility="gone" /> + + + + #66FC0000 #323232 - #424242 - #B3FFFFFF - #77dd77 #67DFE8 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9ff07309ff..ee00a2eab8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1124,5 +1124,6 @@ Error in basal values Error in target values Error in ISF values + Run %s? diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt index b02dfb0dd3..07ac5924d2 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.kt @@ -4,7 +4,6 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.general.automation.actions.Action import info.nightscout.androidaps.plugins.general.automation.actions.ActionDummy -import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy import info.nightscout.androidaps.utils.DateUtil @@ -24,8 +23,9 @@ class AutomationEvent(private val injector: HasAndroidInjector) { var systemAction: Boolean = false // true = generated by AAPS, false = entered by user var readOnly: Boolean = false // removing, editing disabled var autoRemove: Boolean = false // auto-remove once used + var userAction: Boolean = false // shows button on Overview - var trigger: Trigger = TriggerConnector(injector) + var trigger: TriggerConnector = TriggerConnector(injector) val actions: MutableList = ArrayList() var lastRun: Long = 0 @@ -44,7 +44,7 @@ class AutomationEvent(private val injector: HasAndroidInjector) { fun addAction(action: Action) = actions.add(action) - fun areActionsValid() : Boolean { + fun areActionsValid(): Boolean { var result = true for (action in actions) result = result && action.isValid() return result @@ -59,6 +59,7 @@ class AutomationEvent(private val injector: HasAndroidInjector) { .put("systemAction", systemAction) .put("readOnly", readOnly) .put("autoRemove", autoRemove) + .put("userAction", userAction) .put("trigger", trigger.toJSON()) .put("actions", array) .toString() @@ -71,7 +72,8 @@ class AutomationEvent(private val injector: HasAndroidInjector) { systemAction = d.optBoolean("systemAction", false) readOnly = d.optBoolean("readOnly", false) autoRemove = d.optBoolean("autoRemove", false) - trigger = TriggerDummy(injector).instantiate(JSONObject(d.getString("trigger"))) + userAction = d.optBoolean("userAction", false) + trigger = TriggerDummy(injector).instantiate(JSONObject(d.getString("trigger"))) as TriggerConnector val array = d.getJSONArray("actions") actions.clear() for (i in 0 until array.length()) { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt index a0bdaefcb8..47c41918ee 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.kt @@ -100,14 +100,14 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener { .toObservable(EventAutomationUpdateGui::class.java) .observeOn(aapsSchedulers.main) .subscribe({ - updateGui() - }, fabricPrivacy::logException) + updateGui() + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventAutomationDataChanged::class.java) .observeOn(aapsSchedulers.main) .subscribe({ - eventListAdapter.notifyDataSetChanged() - }, fabricPrivacy::logException) + eventListAdapter.notifyDataSetChanged() + }, fabricPrivacy::logException) updateGui() } @@ -167,14 +167,19 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener { @SuppressLint("ClickableViewAccessibility") override fun onBindViewHolder(holder: ViewHolder, position: Int) { val event = automationPlugin.at(position) - holder.binding.rootLayout.setBackgroundColor(resourceHelper.gc(if (event.areActionsValid()) R.color.ribbonDefault else R.color.errorAlertBackground)) + holder.binding.rootLayout.setBackgroundColor(resourceHelper.gc( + if (event.userAction) R.color.mdtp_line_dark + else if (event.areActionsValid()) R.color.ribbonDefault + else R.color.errorAlertBackground) + ) holder.binding.eventTitle.text = event.title holder.binding.enabled.isChecked = event.isEnabled holder.binding.enabled.isEnabled = !event.readOnly holder.binding.iconLayout.removeAllViews() // trigger icons val triggerIcons = HashSet() - fillIconSet(event.trigger as TriggerConnector, triggerIcons) + if (event.userAction) triggerIcons.add(R.drawable.ic_danar_useropt) + fillIconSet(event.trigger, triggerIcons) for (res in triggerIcons) { addImage(res, holder.context, holder.binding.iconLayout) } @@ -217,13 +222,13 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener { // remove event holder.binding.iconTrash.setOnClickListener { OKDialog.showConfirmation(requireContext(), resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title, - { - uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, automationPlugin.at(position).title) - automationPlugin.removeAt(position) - notifyItemRemoved(position) - }, { - rxBus.send(EventAutomationUpdateGui()) - }) + { + uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, automationPlugin.at(position).title) + automationPlugin.removeAt(position) + notifyItemRemoved(position) + }, { + rxBus.send(EventAutomationUpdateGui()) + }) } holder.binding.iconTrash.visibility = (!event.readOnly).toVisibility() holder.binding.aapsLogo.visibility = (event.systemAction).toVisibility() @@ -239,13 +244,15 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener { override fun onItemDismiss(position: Int) { activity?.let { activity -> - OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title, - Runnable { + OKDialog.showConfirmation( + activity, + resourceHelper.gs(R.string.removerecord) + " " + automationPlugin.at(position).title, + { uel.log(Action.AUTOMATION_REMOVED, Sources.Automation, automationPlugin.at(position).title) automationPlugin.removeAt(position) notifyItemRemoved(position) rxBus.send(EventAutomationDataChanged()) - }, Runnable { rxBus.send(EventAutomationUpdateGui()) }) + }, { rxBus.send(EventAutomationUpdateGui()) }) } } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt index ef2828aac0..a09841f903 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.kt @@ -55,17 +55,18 @@ class AutomationPlugin @Inject constructor( private val config: Config, private val locationServiceHelper: LocationServiceHelper, private val dateUtil: DateUtil -) : PluginBase(PluginDescription() - .mainType(PluginType.GENERAL) - .fragmentClass(AutomationFragment::class.qualifiedName) - .pluginIcon(R.drawable.ic_automation) - .pluginName(R.string.automation) - .shortName(R.string.automation_short) - .showInList(config.APS) - .neverVisible(!config.APS) - .alwaysEnabled(!config.APS) - .preferencesId(R.xml.pref_automation) - .description(R.string.automation_description), +) : PluginBase( + PluginDescription() + .mainType(PluginType.GENERAL) + .fragmentClass(AutomationFragment::class.qualifiedName) + .pluginIcon(R.drawable.ic_automation) + .pluginName(R.string.automation) + .shortName(R.string.automation_short) + .showInList(config.APS) + .neverVisible(!config.APS) + .alwaysEnabled(!config.APS) + .preferencesId(R.xml.pref_automation) + .description(R.string.automation_description), aapsLogger, resourceHelper, injector ) { @@ -82,7 +83,8 @@ class AutomationPlugin @Inject constructor( companion object { - const val event = "{\"title\":\"Low\",\"enabled\":true,\"trigger\":\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\",\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"bg\\\\\\\":4,\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\",\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\"}}\\\",\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"value\\\\\\\":-0.1,\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\",\\\\\\\"deltaType\\\\\\\":\\\\\\\"DELTA\\\\\\\",\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\"}}\\\"]}}\",\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget\\\",\\\"data\\\":{\\\"value\\\":8,\\\"units\\\":\\\"mmol\\\",\\\"durationInMinutes\\\":60}}\"]}" + const val event = + "{\"title\":\"Low\",\"enabled\":true,\"trigger\":\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector\\\",\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"bg\\\\\\\":4,\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\",\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\"}}\\\",\\\"{\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDelta\\\\\\\",\\\\\\\"data\\\\\\\":{\\\\\\\"value\\\\\\\":-0.1,\\\\\\\"units\\\\\\\":\\\\\\\"mmol\\\\\\\",\\\\\\\"deltaType\\\\\\\":\\\\\\\"DELTA\\\\\\\",\\\\\\\"comparator\\\\\\\":\\\\\\\"IS_LESSER\\\\\\\"}}\\\"]}}\",\"actions\":[\"{\\\"type\\\":\\\"info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget\\\",\\\"data\\\":{\\\"value\\\":8,\\\"units\\\":\\\"mmol\\\",\\\"durationInMinutes\\\":60}}\"]}" } init { @@ -103,11 +105,11 @@ class AutomationPlugin @Inject constructor( .toObservable(EventPreferenceChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ e -> - if (e.isChanged(resourceHelper, R.string.key_location)) { - locationServiceHelper.stopService(context) - locationServiceHelper.startService(context) - } - }, fabricPrivacy::logException) + if (e.isChanged(resourceHelper, R.string.key_location)) { + locationServiceHelper.stopService(context) + locationServiceHelper.startService(context) + } + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventAutomationDataChanged::class.java) .observeOn(aapsSchedulers.io) @@ -116,11 +118,11 @@ class AutomationPlugin @Inject constructor( .toObservable(EventLocationChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ e -> - e?.let { - aapsLogger.debug(LTag.AUTOMATION, "Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider") - processActions() - } - }, fabricPrivacy::logException) + e?.let { + aapsLogger.debug(LTag.AUTOMATION, "Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider") + processActions() + } + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventChargingState::class.java) .observeOn(aapsSchedulers.io) @@ -137,10 +139,10 @@ class AutomationPlugin @Inject constructor( .toObservable(EventBTChange::class.java) .observeOn(aapsSchedulers.io) .subscribe({ - aapsLogger.debug(LTag.AUTOMATION, "Grabbed new BT event: $it") - btConnects.add(it) - processActions() - }, fabricPrivacy::logException) + aapsLogger.debug(LTag.AUTOMATION, "Grabbed new BT event: $it") + btConnects.add(it) + processActions() + }, fabricPrivacy::logException) } override fun onStop() { @@ -201,40 +203,8 @@ class AutomationPlugin @Inject constructor( val iterator: MutableIterator = automationEvents.iterator() while (iterator.hasNext()) { val event = iterator.next() - if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) { - if (event.systemAction || userEventsEnabled) { - val actions = event.actions - for (action in actions) { - action.title = event.title - if (action.isValid()) - action.doAction(object : Callback() { - override fun run() { - val sb = StringBuilder() - sb.append(dateUtil.timeString(dateUtil.now())) - sb.append(" ") - sb.append(if (result.success) "☺" else "▼") - sb.append(" ") - sb.append(event.title) - sb.append(": ") - sb.append(action.shortDescription()) - sb.append(": ") - sb.append(result.comment) - executionLog.add(sb.toString()) - aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb") - rxBus.send(EventAutomationUpdateGui()) - } - }) - else { - executionLog.add("Invalid action: ${action.shortDescription()}") - aapsLogger.debug(LTag.AUTOMATION, "Invalid action: ${action.shortDescription()}") - rxBus.send(EventAutomationUpdateGui()) - } - } - SystemClock.sleep(1100) - event.lastRun = dateUtil.now() - if (event.autoRemove) automationEvents.remove(event) - } - } + if (event.isEnabled && !event.userAction && event.shouldRun()) + processEvent(event, userEventsEnabled) } // we cannot detect connected BT devices // so let's collect all connection/disconnections between 2 runs of processActions() @@ -245,6 +215,43 @@ class AutomationPlugin @Inject constructor( storeToSP() // save last run time } + fun processEvent(event: AutomationEvent, userEventsEnabled: Boolean) { + if (event.trigger.shouldRun() && event.getPreconditions().shouldRun()) { + if (event.systemAction || userEventsEnabled) { + val actions = event.actions + for (action in actions) { + action.title = event.title + if (action.isValid()) + action.doAction(object : Callback() { + override fun run() { + val sb = StringBuilder() + sb.append(dateUtil.timeString(dateUtil.now())) + sb.append(" ") + sb.append(if (result.success) "☺" else "▼") + sb.append(" ") + sb.append(event.title) + sb.append(": ") + sb.append(action.shortDescription()) + sb.append(": ") + sb.append(result.comment) + executionLog.add(sb.toString()) + aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb") + rxBus.send(EventAutomationUpdateGui()) + } + }) + else { + executionLog.add("Invalid action: ${action.shortDescription()}") + aapsLogger.debug(LTag.AUTOMATION, "Invalid action: ${action.shortDescription()}") + rxBus.send(EventAutomationUpdateGui()) + } + } + SystemClock.sleep(1100) + event.lastRun = dateUtil.now() + if (event.autoRemove) automationEvents.remove(event) + } + } + } + @Synchronized fun add(event: AutomationEvent) { automationEvents.add(event) @@ -283,6 +290,16 @@ class AutomationPlugin @Inject constructor( rxBus.send(EventAutomationDataChanged()) } + fun userEvents(): List { + val list = mutableListOf() + val iterator: MutableIterator = automationEvents.iterator() + while (iterator.hasNext()) { + val event = iterator.next() + if (event.userAction) list.add(event) + } + return list + } + fun getActionDummyObjects(): List { return listOf( //ActionLoopDisable(injector), @@ -318,7 +335,7 @@ class AutomationPlugin @Inject constructor( TriggerAutosensValue(injector), TriggerBolusAgo(injector), TriggerPumpLastConnection(injector), - TriggerBTDevice(injector) + TriggerBTDevice(injector), ) } } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseOperationDialog.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseOperationDialog.kt new file mode 100644 index 0000000000..538d78afca --- /dev/null +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseOperationDialog.kt @@ -0,0 +1,96 @@ +package info.nightscout.androidaps.plugins.general.automation.dialogs + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.RadioButton +import info.nightscout.androidaps.automation.databinding.AutomationDialogChooseOperationBinding +import info.nightscout.androidaps.dialogs.DialogFragmentWithDate +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector +import info.nightscout.androidaps.utils.resources.ResourceHelper +import javax.inject.Inject + +class ChooseOperationDialog : DialogFragmentWithDate() { + + @Inject lateinit var resourceHelper: ResourceHelper + + private var checkedIndex = -1 + + private var _binding: AutomationDialogChooseOperationBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + abstract class Callback : Runnable { + + var result: Int? = null + fun result(result: Int?): Callback { + this.result = result + return this + } + } + + private var callback: Callback? = null + + fun setCallback(callback: Callback): ChooseOperationDialog { + this.callback = callback + return this + } + + fun setCheckedIndex(checkedIndex: Int): ChooseOperationDialog { + this.checkedIndex = checkedIndex + return this + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + // restore checked radio button + savedInstanceState?.let { bundle -> + checkedIndex = bundle.getInt("checkedIndex") + } + + onCreateViewGeneral() + _binding = AutomationDialogChooseOperationBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + for (t in TriggerConnector.Type.labels(resourceHelper)) { + val radioButton = RadioButton(context) + radioButton.text = t + binding.chooseOperationRadioGroup.addView(radioButton) + } + + if (checkedIndex != -1) + (binding.chooseOperationRadioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun submit(): Boolean { + callback?.result(determineCheckedIndex())?.run() + return true + } + + override fun onSaveInstanceState(savedInstanceState: Bundle) { + super.onSaveInstanceState(savedInstanceState) + savedInstanceState.putInt("checkedIndex", determineCheckedIndex()) + } + + private fun determineCheckedIndex(): Int { + for (i in 0 until binding.chooseOperationRadioGroup.childCount) { + if ((binding.chooseOperationRadioGroup.getChildAt(i) as RadioButton).isChecked) + return i + } + return -1 + } +} diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt index 5a069f997d..43a1025eff 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.kt @@ -13,6 +13,7 @@ import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.automation.databinding.AutomationDialogEventBinding import info.nightscout.androidaps.dialogs.DialogFragmentWithDate +import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.automation.AutomationEvent import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin @@ -22,13 +23,11 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventAutomat import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateAction import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger -import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.ToastUtils -import io.reactivex.rxkotlin.plusAssign -import info.nightscout.androidaps.extensions.toVisibility import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import javax.inject.Inject class EditEventDialog : DialogFragmentWithDate() { @@ -73,6 +72,8 @@ class EditEventDialog : DialogFragmentWithDate() { binding.inputEventTitle.setText(event.title) binding.inputEventTitle.isFocusable = !event.readOnly binding.triggerDescription.text = event.trigger.friendlyDescription() + binding.userAction.isChecked = event.userAction + binding.enabled.isChecked = event.isEnabled binding.editTrigger.visibility = (!event.readOnly).toVisibility() binding.editTrigger.setOnClickListener { @@ -131,9 +132,11 @@ class EditEventDialog : DialogFragmentWithDate() { return false } event.title = title + event.userAction = binding.userAction.isChecked + event.isEnabled = binding.enabled.isChecked // check for at least one trigger - val con = event.trigger as TriggerConnector - if (con.size() == 0) { + val con = event.trigger + if (con.size() == 0 && !event.userAction) { ToastUtils.showToastInUiThread(context, R.string.automation_missing_trigger) return false } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt index 6d1de70e37..24281a91bc 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.kt @@ -16,9 +16,9 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy import info.nightscout.androidaps.utils.FabricPrivacy -import io.reactivex.rxkotlin.plusAssign import info.nightscout.androidaps.utils.rx.AapsSchedulers import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.plusAssign import org.json.JSONObject import javax.inject.Inject @@ -31,7 +31,7 @@ class EditTriggerDialog : DialogFragmentWithDate() { private var disposable: CompositeDisposable = CompositeDisposable() - private var triggers: Trigger? = null + private var triggers: TriggerConnector? = null private var _binding: AutomationDialogEditTriggerBinding? = null @@ -39,11 +39,13 @@ class EditTriggerDialog : DialogFragmentWithDate() { // onDestroyView. private val binding get() = _binding!! - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View { + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { // load data from bundle (savedInstanceState ?: arguments)?.let { bundle -> - bundle.getString("trigger")?.let { triggers = TriggerDummy(injector).instantiate(JSONObject(it)) } + bundle.getString("trigger")?.let { triggers = TriggerDummy(injector).instantiate(JSONObject(it)) as TriggerConnector } } onCreateViewGeneral() @@ -58,26 +60,26 @@ class EditTriggerDialog : DialogFragmentWithDate() { .toObservable(EventTriggerChanged::class.java) .observeOn(aapsSchedulers.main) .subscribe({ - binding.layoutTrigger.removeAllViews() - triggers?.generateDialog(binding.layoutTrigger) - }, fabricPrivacy::logException) + binding.layoutTrigger.removeAllViews() + triggers?.generateDialog(binding.layoutTrigger) + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventTriggerRemove::class.java) .observeOn(aapsSchedulers.main) .subscribe({ - findParent(triggers, it.trigger)?.list?.remove(it.trigger) - binding.layoutTrigger.removeAllViews() - triggers?.generateDialog(binding.layoutTrigger) - }, fabricPrivacy::logException) + findParent(triggers, it.trigger)?.list?.remove(it.trigger) + binding.layoutTrigger.removeAllViews() + triggers?.generateDialog(binding.layoutTrigger) + }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventTriggerClone::class.java) .observeOn(aapsSchedulers.main) .subscribe({ - findParent(triggers, it.trigger)?.list?.add(it.trigger.duplicate()) - binding.layoutTrigger.removeAllViews() - triggers?.generateDialog(binding.layoutTrigger) - }, fabricPrivacy::logException) + findParent(triggers, it.trigger)?.list?.add(it.trigger.duplicate()) + binding.layoutTrigger.removeAllViews() + triggers?.generateDialog(binding.layoutTrigger) + }, fabricPrivacy::logException) // display root trigger triggers?.generateDialog(binding.layoutTrigger) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/Comparator.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/Comparator.kt index 97f80e4460..dd872a88c5 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/Comparator.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/Comparator.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter @@ -42,6 +43,7 @@ class Comparator(private val resourceHelper: ResourceHelper) : Element() { } companion object { + fun labels(resourceHelper: ResourceHelper): List { val list: MutableList = ArrayList() for (c in values()) { @@ -59,25 +61,24 @@ class Comparator(private val resourceHelper: ResourceHelper) : Element() { var value = Compare.IS_EQUAL override fun addToLayout(root: LinearLayout) { - val spinner = Spinner(root.context) - val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.labels(resourceHelper)) - spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = spinnerArrayAdapter - val spinnerParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) - spinner.layoutParams = spinnerParams - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - value = Compare.values()[position] - } + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.labels(resourceHelper)).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, resourceHelper.dpToPx(1), 0, resourceHelper.dpToPx(1)) + } + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + value = Compare.values()[position] + } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - spinner.setSelection(value.ordinal) - root.addView(spinner) + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + setSelection(value.ordinal) + gravity = Gravity.CENTER_HORIZONTAL + }) } fun setValue(compare: Compare): Comparator { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorConnect.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorConnect.kt index d27b0c4ee5..60d49c49eb 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorConnect.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorConnect.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter @@ -16,11 +17,12 @@ class ComparatorConnect(private val resourceHelper: ResourceHelper) : Element() @get:StringRes val stringRes: Int get() = when (this) { - ON_CONNECT -> R.string.onconnect + ON_CONNECT -> R.string.onconnect ON_DISCONNECT -> R.string.ondisconnect } companion object { + fun labels(resourceHelper: ResourceHelper): List { val list: MutableList = ArrayList() for (c in values()) list.add(resourceHelper.gs(c.stringRes)) @@ -36,21 +38,24 @@ class ComparatorConnect(private val resourceHelper: ResourceHelper) : Element() var value = Compare.ON_CONNECT override fun addToLayout(root: LinearLayout) { - val spinner = Spinner(root.context) - val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.labels(resourceHelper)) - spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = spinnerArrayAdapter - val spinnerParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) - spinner.layoutParams = spinnerParams - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - value = Compare.values()[position] - } + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.labels(resourceHelper)).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - spinner.setSelection(value.ordinal) - root.addView(spinner) + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) + } + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + value = Compare.values()[position] + } + + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + setSelection(value.ordinal) + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorExists.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorExists.kt index 9337dd93fb..0812d7c798 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorExists.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/ComparatorExists.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter @@ -16,11 +17,12 @@ class ComparatorExists(private val resourceHelper: ResourceHelper, var value: Co @get:StringRes val stringRes: Int get() = when (this) { - EXISTS -> R.string.exists + EXISTS -> R.string.exists NOT_EXISTS -> R.string.notexists } companion object { + fun labels(resourceHelper: ResourceHelper): List { val list: MutableList = ArrayList() for (c in values()) list.add(resourceHelper.gs(c.stringRes)) @@ -30,21 +32,24 @@ class ComparatorExists(private val resourceHelper: ResourceHelper, var value: Co } override fun addToLayout(root: LinearLayout) { - val spinner = Spinner(root.context) - val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.labels(resourceHelper)) - spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = spinnerArrayAdapter - val spinnerParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) - spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) - spinner.layoutParams = spinnerParams - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - value = Compare.values()[position] - } + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.labels(resourceHelper)).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) + } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - spinner.setSelection(value.ordinal) - root.addView(spinner) + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + value = Compare.values()[position] + } + + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + setSelection(value.ordinal) + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.kt index 59f638dc17..072149a64d 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputBg.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.widget.LinearLayout import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.interfaces.GlucoseUnit @@ -26,13 +27,15 @@ class InputBg(profileFunction: ProfileFunction) : Element() { } override fun addToLayout(root: LinearLayout) { - val numberPicker = NumberPicker(root.context, null) - numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, false, root.findViewById(R.id.ok)) - numberPicker.setOnValueChangedListener { value: Double -> this.value = value } - root.addView(numberPicker) + root.addView( + NumberPicker(root.context, null).apply { + setParams(value, minValue, maxValue, step, decimalFormat, false, root.findViewById(R.id.ok)) + setOnValueChangedListener { value: Double -> this.value = value } + gravity = Gravity.CENTER_HORIZONTAL + }) } - fun setValue(value: Double) : InputBg { + fun setValue(value: Double): InputBg { this.value = value return this } @@ -54,6 +57,7 @@ class InputBg(profileFunction: ProfileFunction) : Element() { } companion object { + const val MMOL_MIN = 3.0 const val MMOL_MAX = 20.0 const val MGDL_MIN = 54.0 diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputButton.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputButton.kt index cd9773fd69..216f54e3fd 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputButton.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputButton.kt @@ -1,9 +1,11 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.widget.Button import android.widget.LinearLayout class InputButton() : Element() { + var text: String? = null var runnable: Runnable? = null @@ -13,9 +15,11 @@ class InputButton() : Element() { } override fun addToLayout(root: LinearLayout) { - val button = Button(root.context) - button.text = text - button.setOnClickListener { runnable?.run() } - root.addView(button) + root.addView( + Button(root.context).apply { + text = text + setOnClickListener { runnable?.run() } + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputCarePortalMenu.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputCarePortalMenu.kt index 19b1701c60..5ac9798ae2 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputCarePortalMenu.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputCarePortalMenu.kt @@ -1,51 +1,50 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.LinearLayout import android.widget.Spinner import androidx.annotation.DrawableRes -import androidx.annotation.LayoutRes import androidx.annotation.StringRes -import androidx.core.graphics.drawable.IconCompat import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.database.entities.TherapyEvent -import info.nightscout.androidaps.database.entities.UserEntry import info.nightscout.androidaps.utils.resources.ResourceHelper class InputCarePortalMenu(private val resourceHelper: ResourceHelper) : Element() { - enum class EventType (val therapyEventType: TherapyEvent.Type) { - NOTE (TherapyEvent.Type.NOTE), - EXERCISE (TherapyEvent.Type.EXERCISE), - QUESTION (TherapyEvent.Type.QUESTION), - ANNOUNCEMENT (TherapyEvent.Type.ANNOUNCEMENT); + enum class EventType(val therapyEventType: TherapyEvent.Type) { + NOTE(TherapyEvent.Type.NOTE), + EXERCISE(TherapyEvent.Type.EXERCISE), + QUESTION(TherapyEvent.Type.QUESTION), + ANNOUNCEMENT(TherapyEvent.Type.ANNOUNCEMENT); @get:StringRes val stringResWithValue: Int get() = when (this) { - NOTE -> R.string.careportal_note_message - EXERCISE -> R.string.careportal_exercise_message - QUESTION -> R.string.careportal_question_message - ANNOUNCEMENT -> R.string.careportal_announcement_message + NOTE -> R.string.careportal_note_message + EXERCISE -> R.string.careportal_exercise_message + QUESTION -> R.string.careportal_question_message + ANNOUNCEMENT -> R.string.careportal_announcement_message } @get:StringRes val stringRes: Int get() = when (this) { - NOTE -> R.string.careportal_note - EXERCISE -> R.string.careportal_exercise - QUESTION -> R.string.careportal_question - ANNOUNCEMENT -> R.string.careportal_announcement + NOTE -> R.string.careportal_note + EXERCISE -> R.string.careportal_exercise + QUESTION -> R.string.careportal_question + ANNOUNCEMENT -> R.string.careportal_announcement } @get:DrawableRes val drawableRes: Int get() = when (this) { - NOTE -> R.drawable.ic_cp_note - EXERCISE -> R.drawable.ic_cp_exercise - QUESTION -> R.drawable.ic_cp_question - ANNOUNCEMENT -> R.drawable.ic_cp_announcement + NOTE -> R.drawable.ic_cp_note + EXERCISE -> R.drawable.ic_cp_exercise + QUESTION -> R.drawable.ic_cp_question + ANNOUNCEMENT -> R.drawable.ic_cp_announcement } companion object { + fun labels(resourceHelper: ResourceHelper): List { val list: MutableList = ArrayList() for (e in values()) { @@ -63,25 +62,25 @@ class InputCarePortalMenu(private val resourceHelper: ResourceHelper) : Element( var value = EventType.NOTE override fun addToLayout(root: LinearLayout) { - val spinner = Spinner(root.context) - val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, EventType.labels(resourceHelper)) - spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = spinnerArrayAdapter - val spinnerParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) - spinner.layoutParams = spinnerParams - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - value = EventType.values()[position] - } + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, EventType.labels(resourceHelper)).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) + } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - spinner.setSelection(value.ordinal) - root.addView(spinner) + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + value = EventType.values()[position] + } + + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + setSelection(value.ordinal) + gravity = Gravity.CENTER_HORIZONTAL + }) } fun setValue(eventType: EventType): InputCarePortalMenu { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt index df0939bfa7..2ded79d1d9 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDateTime.kt @@ -15,71 +15,71 @@ import java.util.* class InputDateTime(private val resourceHelper: ResourceHelper, private val dateUtil: DateUtil, var value: Long = dateUtil.now()) : Element() { override fun addToLayout(root: LinearLayout) { - val label = TextView(root.context) - val dateButton = TextView(root.context) - val timeButton = TextView(root.context) - dateButton.text = dateUtil.dateString(value) - timeButton.text = dateUtil.timeString(value) - - // create an OnDateSetListener - val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth -> - val cal = Calendar.getInstance() - cal.timeInMillis = value - cal.set(Calendar.YEAR, year) - cal.set(Calendar.MONTH, monthOfYear) - cal.set(Calendar.DAY_OF_MONTH, dayOfMonth) - value = cal.timeInMillis - dateButton.text = dateUtil.dateString(value) - } - - dateButton.setOnClickListener { - root.context?.let { - val cal = Calendar.getInstance() - cal.timeInMillis = value - DatePickerDialog(it, dateSetListener, - cal.get(Calendar.YEAR), - cal.get(Calendar.MONTH), - cal.get(Calendar.DAY_OF_MONTH) - ).show() - } - } - - // create an OnTimeSetListener - val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute -> - val cal = Calendar.getInstance() - cal.timeInMillis = value - cal.set(Calendar.HOUR_OF_DAY, hour) - cal.set(Calendar.MINUTE, minute) - cal.set(Calendar.SECOND, 0) // randomize seconds to prevent creating record of the same time, if user choose time manually - value = cal.timeInMillis - timeButton.text = dateUtil.timeString(value) - } - - timeButton.setOnClickListener { - root.context?.let { - val cal = Calendar.getInstance() - cal.timeInMillis = value - TimePickerDialog(it, timeSetListener, - cal.get(Calendar.HOUR_OF_DAY), - cal.get(Calendar.MINUTE), - DateFormat.is24HourFormat(it) - ).show() - } - } - val px = resourceHelper.dpToPx(10) - label.text = resourceHelper.gs(R.string.atspecifiedtime, "") - label.setTypeface(label.typeface, Typeface.BOLD) - label.setPadding(px, px, px, px) - dateButton.setPadding(px, px, px, px) - timeButton.setPadding(px, px, px, px) - val l = LinearLayout(root.context) - l.orientation = LinearLayout.HORIZONTAL - l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - l.addView(label) - l.addView(dateButton) - l.addView(timeButton) - root.addView(l) - } + root.addView( + LinearLayout(root.context).apply { + orientation = LinearLayout.HORIZONTAL + layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + addView( + TextView(root.context).apply { + text = resourceHelper.gs(R.string.atspecifiedtime, "") + setTypeface(typeface, Typeface.BOLD) + setPadding(px, px, px, px) + }) + addView( + TextView(root.context).apply { + text = dateUtil.dateString(value) + setPadding(px, px, px, px) + setOnClickListener { + root.context?.let { + val cal = Calendar.getInstance() + cal.timeInMillis = value + DatePickerDialog( + it, + { _, year, monthOfYear, dayOfMonth -> + value = Calendar.getInstance().apply { + timeInMillis = value + set(Calendar.YEAR, year) + set(Calendar.MONTH, monthOfYear) + set(Calendar.DAY_OF_MONTH, dayOfMonth) + }.timeInMillis + text = dateUtil.dateString(value) + }, + cal.get(Calendar.YEAR), + cal.get(Calendar.MONTH), + cal.get(Calendar.DAY_OF_MONTH) + ).show() + } + } + }) + addView( + TextView(root.context).apply { + text = dateUtil.timeString(value) + setPadding(px, px, px, px) + setOnClickListener { + root.context?.let { + val cal = Calendar.getInstance() + cal.timeInMillis = value + TimePickerDialog( + it, + { _, hour, minute -> + value = Calendar.getInstance().apply { + timeInMillis = value + set(Calendar.HOUR_OF_DAY, hour) + set(Calendar.MINUTE, minute) + set(Calendar.SECOND, 0) // randomize seconds to prevent creating record of the same time, if user choose time manually + }.timeInMillis + text = dateUtil.timeString(value) + }, + cal.get(Calendar.HOUR_OF_DAY), + cal.get(Calendar.MINUTE), + DateFormat.is24HourFormat(it) + ).show() + } + } + } + ) + }) + } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.kt index 365de3c2dd..8ce6f6de09 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDelta.kt @@ -1,15 +1,15 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View -import android.view.ViewGroup import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.LinearLayout import android.widget.Spinner import androidx.annotation.StringRes import info.nightscout.androidaps.automation.R -import info.nightscout.androidaps.utils.ui.NumberPicker import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.ui.NumberPicker import java.text.DecimalFormat class InputDelta(private val resourceHelper: ResourceHelper) : Element() { @@ -19,12 +19,13 @@ class InputDelta(private val resourceHelper: ResourceHelper) : Element() { @get:StringRes val stringRes: Int get() = when (this) { - DELTA -> R.string.delta + DELTA -> R.string.delta SHORT_AVERAGE -> R.string.short_avgdelta - LONG_AVERAGE -> R.string.long_avgdelta + LONG_AVERAGE -> R.string.long_avgdelta } companion object { + fun labels(resourceHelper: ResourceHelper): List { val list: MutableList = ArrayList() for (d in values()) { @@ -61,32 +62,29 @@ class InputDelta(private val resourceHelper: ResourceHelper) : Element() { } override fun addToLayout(root: LinearLayout) { - val spinner = Spinner(root.context) - val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, DeltaType.labels(resourceHelper)) - spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = spinnerArrayAdapter - val spinnerParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) - spinner.layoutParams = spinnerParams - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - deltaType = DeltaType.values()[position] - } + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, DeltaType.labels(resourceHelper)).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) + } + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + deltaType = DeltaType.values()[position] + } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - spinner.setSelection(deltaType.ordinal) - val numberPicker = NumberPicker(root.context, null) - numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, null) - numberPicker.setOnValueChangedListener { value: Double -> this.value = value } - val l = LinearLayout(root.context) - l.orientation = LinearLayout.VERTICAL - l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) - l.addView(spinner) - l.addView(numberPicker) - root.addView(l) + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + setSelection(deltaType.ordinal) + gravity = Gravity.CENTER_HORIZONTAL + }) + root.addView( + NumberPicker(root.context, null).apply { + setParams(value, minValue, maxValue, step, decimalFormat, true, null, null) + setOnValueChangedListener { value: Double -> this.value = value } + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDouble.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDouble.kt index d6f975fa78..44fe1091b7 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDouble.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDouble.kt @@ -1,11 +1,13 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.widget.LinearLayout import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.utils.ui.NumberPicker import java.text.DecimalFormat class InputDouble() : Element() { + var value = 0.0 private var minValue = 0.0 private var maxValue = 0.0 @@ -30,9 +32,11 @@ class InputDouble() : Element() { } override fun addToLayout(root: LinearLayout) { - numberPicker = NumberPicker(root.context, null) - numberPicker?.setParams(value, minValue, maxValue, step, decimalFormat, true, root.findViewById(R.id.ok)) - numberPicker?.setOnValueChangedListener { value: Double -> this.value = value } + numberPicker = NumberPicker(root.context, null).apply { + setParams(value, minValue, maxValue, step, decimalFormat, true, root.findViewById(R.id.ok)) + setOnValueChangedListener { value: Double -> this.value = value } + gravity = Gravity.CENTER_HORIZONTAL + } root.addView(numberPicker) } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDropdownMenu.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDropdownMenu.kt index 3bf7110d6d..7ec5dbc62e 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDropdownMenu.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDropdownMenu.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View -import android.view.ViewGroup import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.LinearLayout @@ -25,31 +25,25 @@ class InputDropdownMenu(private val resourceHelper: ResourceHelper) : Element() } override fun addToLayout(root: LinearLayout) { - val spinner = Spinner(root.context) - spinner.adapter = ArrayAdapter( - root.context, - R.layout.spinner_centered, itemList - ).also { - it.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - } - spinner.layoutParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ).also { it.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) } + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, itemList).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).also { + it.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) + } - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - setValue(itemList[position].toString()) - } + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + setValue(itemList[position].toString()) + } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - for (i in 0 until itemList.size) if (itemList[i] == value) spinner.setSelection(i) - root.addView(LinearLayout(root.context).also { - it.orientation = LinearLayout.VERTICAL - it.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) - it.addView(spinner) - }) + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + gravity = Gravity.CENTER_HORIZONTAL + for (i in 0 until itemList.size) if (itemList[i] == value) setSelection(i) + }) } fun setValue(name: String): InputDropdownMenu { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDuration.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDuration.kt index 1ae61ced9a..a20e509b19 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDuration.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDuration.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.widget.LinearLayout import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.utils.ui.MinutesNumberPicker @@ -25,6 +26,7 @@ class InputDuration( numberPicker.setParams(value.toDouble(), 1.0, 24.0, 1.0, DecimalFormat("0"), false, root.findViewById(R.id.ok)) } numberPicker.setOnValueChangedListener { value: Double -> this.value = value.toInt() } + numberPicker.gravity = Gravity.CENTER_HORIZONTAL root.addView(numberPicker) } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputInsulin.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputInsulin.kt index 038449f6eb..94941ffa8d 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputInsulin.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputInsulin.kt @@ -1,11 +1,13 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.widget.LinearLayout import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.utils.ui.NumberPicker import java.text.DecimalFormat class InputInsulin() : Element() { + var value = 0.0 constructor(another: InputInsulin) : this() { @@ -13,10 +15,12 @@ class InputInsulin() : Element() { } override fun addToLayout(root: LinearLayout) { - val numberPicker = NumberPicker(root.context, null) - numberPicker.setParams(0.0, -20.0, 20.0, 0.1, DecimalFormat("0.0"), true, root.findViewById(R.id.ok)) - numberPicker.value = value - numberPicker.setOnValueChangedListener { value: Double -> this.value = value } - root.addView(numberPicker) + root.addView( + NumberPicker(root.context, null).apply { + setParams(0.0, -20.0, 20.0, 0.1, DecimalFormat("0.0"), true, root.findViewById(R.id.ok)) + value = value + setOnValueChangedListener { value: Double -> this.value = value } + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputLocationMode.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputLocationMode.kt index 2174da6425..234d2016e3 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputLocationMode.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputLocationMode.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter @@ -30,6 +31,7 @@ class InputLocationMode(private val resourceHelper: ResourceHelper) : Element() } companion object { + fun labels(resourceHelper: ResourceHelper): List { val list: MutableList = ArrayList() for (c in values()) { @@ -47,24 +49,24 @@ class InputLocationMode(private val resourceHelper: ResourceHelper) : Element() } override fun addToLayout(root: LinearLayout) { - val adapter = ArrayAdapter(root.context, R.layout.spinner_centered, Mode.labels(resourceHelper)) - val spinner = Spinner(root.context) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = adapter - val spinnerParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) - spinner.layoutParams = spinnerParams - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - value = Mode.values()[position] - } + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, Mode.labels(resourceHelper)).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + val spinnerParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) + } + layoutParams = spinnerParams + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + value = Mode.values()[position] + } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - spinner.setSelection(value.ordinal) - root.addView(spinner) + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + setSelection(value.ordinal) + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.kt index ffb27badfe..d7077692b4 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.widget.LinearLayout import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.utils.ui.NumberPicker @@ -14,11 +15,13 @@ class InputPercent() : Element() { } override fun addToLayout(root: LinearLayout) { - val numberPicker = NumberPicker(root.context, null) - numberPicker.setParams(100.0, MIN, MAX, 5.0, DecimalFormat("0"), true, root.findViewById(R.id.ok)) - numberPicker.value = value - numberPicker.setOnValueChangedListener { value: Double -> this.value = value } - root.addView(numberPicker) + root.addView( + NumberPicker(root.context, null).apply { + setParams(100.0, MIN, MAX, 5.0, DecimalFormat("0"), true, root.findViewById(R.id.ok)) + value = value + setOnValueChangedListener { value: Double -> this.value = value } + gravity = Gravity.CENTER_HORIZONTAL + }) } companion object { diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt index a6f464bafe..6af8d3ab9a 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputProfileName.kt @@ -1,7 +1,7 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.view.View -import android.view.ViewGroup import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.LinearLayout @@ -17,28 +17,24 @@ class InputProfileName(private val resourceHelper: ResourceHelper, private val a override fun addToLayout(root: LinearLayout) { val profileStore = activePlugin.activeProfileSource.profile ?: return val profileList = profileStore.getProfileList() - val adapter = ArrayAdapter(root.context, R.layout.spinner_centered, profileList) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - val spinner = Spinner(root.context) - spinner.adapter = adapter - val spinnerParams = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) - spinner.layoutParams = spinnerParams - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - value = profileList[position].toString() - } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - for (i in 0 until profileList.size) if (profileList[i] == value) spinner.setSelection(i) - val l = LinearLayout(root.context) - l.orientation = LinearLayout.VERTICAL - l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) - l.addView(spinner) - root.addView(l) + root.addView( + Spinner(root.context).apply { + adapter = ArrayAdapter(root.context, R.layout.spinner_centered, profileList).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) + } + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + value = profileList[position].toString() + } + + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + for (i in 0 until profileList.size) if (profileList[i] == value) setSelection(i) + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputString.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputString.kt index 7ef46bd7a9..dd24d0f993 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputString.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputString.kt @@ -2,11 +2,13 @@ package info.nightscout.androidaps.plugins.general.automation.elements import android.text.Editable import android.text.TextWatcher +import android.view.Gravity import android.view.ViewGroup import android.widget.EditText import android.widget.LinearLayout class InputString(var value: String = "") : Element() { + private val textWatcher: TextWatcher = object : TextWatcher { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} @@ -16,10 +18,12 @@ class InputString(var value: String = "") : Element() { } override fun addToLayout(root: LinearLayout) { - val editText = EditText(root.context) - editText.setText(value) - editText.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - editText.addTextChangedListener(textWatcher) - root.addView(editText) + root.addView( + EditText(root.context).apply { + setText(value) + layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + addTextChangedListener(textWatcher) + gravity = Gravity.CENTER_HORIZONTAL + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTempTarget.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTempTarget.kt index 31a2c1b64a..444d92ba8a 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTempTarget.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTempTarget.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.view.Gravity import android.widget.LinearLayout import info.nightscout.androidaps.Constants import info.nightscout.androidaps.automation.R @@ -9,6 +10,7 @@ import info.nightscout.androidaps.utils.ui.NumberPicker import java.text.DecimalFormat class InputTempTarget(profileFunction: ProfileFunction) : Element() { + var units: GlucoseUnit = GlucoseUnit.MGDL var value = 0.0 @@ -38,9 +40,12 @@ class InputTempTarget(profileFunction: ProfileFunction) : Element() { step = 1.0 decimalFormat = DecimalFormat("0") } - val numberPicker = NumberPicker(root.context, null) - numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, root.findViewById(R.id.ok)) - numberPicker.setOnValueChangedListener { value: Double -> this.value = value } - root.addView(numberPicker) + root.addView( + NumberPicker(root.context, null).apply { + setParams(value, minValue, maxValue, step, decimalFormat, true, root.findViewById(R.id.ok)) + setOnValueChangedListener { value: Double -> this.value = value } + gravity = Gravity.CENTER_HORIZONTAL + + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt index 36f93bbe01..bdb9e66bd0 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTime.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.automation.elements import android.app.TimePickerDialog import android.graphics.Typeface import android.text.format.DateFormat +import android.view.Gravity import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView @@ -18,37 +19,38 @@ class InputTime(private val resourceHelper: ResourceHelper, private val dateUtil var value: Int = getMinSinceMidnight(dateUtil.now()) override fun addToLayout(root: LinearLayout) { - val label = TextView(root.context) - val startButton = TextView(root.context) - startButton.text = dateUtil.timeString(toMills(value)) - - val startTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute -> - value = 60 * hour + minute - startButton.text = dateUtil.timeString(toMills(value)) - } - - startButton.setOnClickListener { - root.context?.let { - val cal = Calendar.getInstance() - cal.timeInMillis = toMills(value) - TimePickerDialog(it, startTimeSetListener, - cal.get(Calendar.HOUR_OF_DAY), - cal.get(Calendar.MINUTE), - DateFormat.is24HourFormat(it) - ).show() - } - } - - val px = resourceHelper.dpToPx(10) - label.text = resourceHelper.gs(R.string.atspecifiedtime, "") - label.setTypeface(label.typeface, Typeface.BOLD) - startButton.setPadding(px, px, px, px) - val l = LinearLayout(root.context) - l.orientation = LinearLayout.HORIZONTAL - l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - l.addView(label) - l.addView(startButton) - root.addView(l) + root.addView( + LinearLayout(root.context).apply { + orientation = LinearLayout.HORIZONTAL + layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + addView( + TextView(root.context).apply { + text = resourceHelper.gs(R.string.atspecifiedtime, "") + setTypeface(typeface, Typeface.BOLD) + }) + addView( + TextView(root.context).apply { + text = dateUtil.timeString(toMills(value)) + val px = resourceHelper.dpToPx(10) + setPadding(px, px, px, px) + setOnClickListener { + root.context?.let { + val cal = Calendar.getInstance() + cal.timeInMillis = toMills(value) + TimePickerDialog( + it, + { _, hour, minute -> + value = 60 * hour + minute + text = dateUtil.timeString(toMills(value)) + }, + cal.get(Calendar.HOUR_OF_DAY), + cal.get(Calendar.MINUTE), + DateFormat.is24HourFormat(it) + ).show() + } + } + }) + }) } private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calcPlusMinutes(minutesSinceMidnight) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt index c9873da2bf..e011d7ee54 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputTimeRange.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.automation.elements import android.app.TimePickerDialog import android.graphics.Typeface import android.text.format.DateFormat +import android.view.Gravity import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView @@ -19,59 +20,62 @@ class InputTimeRange(private val resourceHelper: ResourceHelper, private val dat var end: Int = getMinSinceMidnight(dateUtil.now()) override fun addToLayout(root: LinearLayout) { - val label = TextView(root.context) - val startButton = TextView(root.context) - val endButton = TextView(root.context) - startButton.text = dateUtil.timeString(toMills(start)) - @Suppress("SetTextI18n") - endButton.text = resourceHelper.gs(R.string.and) + " " + dateUtil.timeString(toMills(end)) - - val startTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute -> - start = 60 * hour + minute - startButton.text = dateUtil.timeString(toMills(start)) - } - - startButton.setOnClickListener { - root.context?.let { - val cal = Calendar.getInstance() - cal.timeInMillis = toMills(start) - TimePickerDialog(it, startTimeSetListener, - cal.get(Calendar.HOUR_OF_DAY), - cal.get(Calendar.MINUTE), - DateFormat.is24HourFormat(it) - ).show() - } - } - - val endTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute -> - end = 60 * hour + minute - endButton.text = dateUtil.timeString(toMills(end)) - } - - endButton.setOnClickListener { - root.context?.let { - val cal = Calendar.getInstance() - cal.timeInMillis = toMills(end) - TimePickerDialog(it, endTimeSetListener, - cal.get(Calendar.HOUR_OF_DAY), - cal.get(Calendar.MINUTE), - DateFormat.is24HourFormat(it) - ).show() - } - } - val px = resourceHelper.dpToPx(10) - label.text = resourceHelper.gs(R.string.between) - label.setTypeface(label.typeface, Typeface.BOLD) - startButton.setPadding(px, px, px, px) - endButton.setPadding(px, px, px, px) - val l = LinearLayout(root.context) - l.orientation = LinearLayout.HORIZONTAL - l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - l.addView(label) - l.addView(startButton) - l.addView(endButton) - root.addView(l) + + root.addView( + TextView(root.context).apply { + text = resourceHelper.gs(R.string.between) + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER_HORIZONTAL + }) + root.addView( + LinearLayout(root.context).apply { + orientation = LinearLayout.HORIZONTAL + layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + gravity = Gravity.CENTER_HORIZONTAL + addView( + TextView(root.context).apply { + text = dateUtil.timeString(toMills(start)) + setPadding(px, px, px, px) + setOnClickListener { + root.context?.let { + val cal = Calendar.getInstance() + cal.timeInMillis = toMills(start) + TimePickerDialog( + it, + { _, hour, minute -> + start = 60 * hour + minute + text = dateUtil.timeString(toMills(start)) + }, + cal.get(Calendar.HOUR_OF_DAY), + cal.get(Calendar.MINUTE), + DateFormat.is24HourFormat(it) + ).show() + } + } + }) + addView(TextView(root.context).apply { + @Suppress("SetTextI18n") + text = resourceHelper.gs(R.string.and) + " " + dateUtil.timeString(toMills(end)) + setPadding(px, px, px, px) + setOnClickListener { + root.context?.let { + val cal = Calendar.getInstance() + cal.timeInMillis = toMills(end) + TimePickerDialog( + it, + { _, hour, minute -> + end = 60 * hour + minute + text = dateUtil.timeString(toMills(end)) + }, + cal.get(Calendar.HOUR_OF_DAY), + cal.get(Calendar.MINUTE), + DateFormat.is24HourFormat(it) + ).show() + } + } + }) + }) } private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calcPlusMinutes(minutesSinceMidnight) diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt index 359e252f97..c34a53444c 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputWeekDay.kt @@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.general.automation.elements import android.widget.LinearLayout import androidx.annotation.StringRes -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.utils.ui.WeekdayPicker import java.util.* @@ -20,6 +19,7 @@ class InputWeekDay : Element() { get() = shortNames[ordinal] companion object { + private val calendarInts = intArrayOf( Calendar.MONDAY, Calendar.TUESDAY, @@ -76,10 +76,11 @@ class InputWeekDay : Element() { } override fun addToLayout(root: LinearLayout) { - WeekdayPicker(root.context).apply { - setSelectedDays(getSelectedDays()) - setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) } - root.addView(this) - } + root.addView( + WeekdayPicker(root.context).apply { + setSelectedDays(getSelectedDays()) + setOnWeekdaysChangeListener { i: Int, selected: Boolean -> set(DayOfWeek.fromCalendarInt(i), selected) } + } + ) } } diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt index adc29fdb1e..d69e3504d5 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LabelWithElement.kt @@ -1,9 +1,8 @@ package info.nightscout.androidaps.plugins.general.automation.elements import android.graphics.Typeface -import android.view.ViewGroup +import android.view.Gravity import android.widget.LinearLayout -import android.widget.TableLayout import android.widget.TextView import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -15,35 +14,27 @@ class LabelWithElement( ) : Element() { override fun addToLayout(root: LinearLayout) { // container layout - val layout = LinearLayout(root.context) - layout.orientation = LinearLayout.HORIZONTAL - layout.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT) // text view pre element - var px = resourceHelper.dpToPx(10) - val textViewPre = TextView(root.context) - textViewPre.text = textPre - textViewPre.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT) - textViewPre.setPadding(px, px, px, px) - textViewPre.setTypeface(textViewPre.typeface, Typeface.BOLD) - layout.addView(textViewPre) - val spacer = TextView(root.context) - spacer.layoutParams = TableLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) - layout.addView(spacer) - // add element to layout - element?.addToLayout(layout) - // text view post element - px = resourceHelper.dpToPx(5) - val textViewPost = TextView(root.context) - textViewPost.text = textPost - textViewPost.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT) - textViewPost.setPadding(px, px, px, px) - textViewPost.setTypeface(textViewPost.typeface, Typeface.BOLD) - layout.addView(textViewPost) - // add layout to root layout - root.addView(layout) - } + val px = resourceHelper.dpToPx(1) + root.addView( + TextView(root.context).apply { + text = textPre + setPadding(px, px, px, px) + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER + } + ) + + // add element to layout + element?.addToLayout(root) + // text view post element + root.addView( + TextView(root.context).apply { + text = textPost + setPadding(px, px, px, px) + setTypeface(typeface, Typeface.BOLD) + gravity = Gravity.CENTER + }) + } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.kt index 0bf18e383d..0c87f393d2 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.kt @@ -1,6 +1,10 @@ package info.nightscout.androidaps.plugins.general.automation.elements +import android.content.Context +import android.view.Gravity +import android.view.ViewGroup import android.widget.LinearLayout +import info.nightscout.androidaps.automation.R class LayoutBuilder { @@ -16,8 +20,21 @@ class LayoutBuilder { } fun build(layout: LinearLayout) { - for (e in mElements) { - e.addToLayout(layout) + val elementLayout = LinearLayout(layout.context).apply { + orientation = LinearLayout.VERTICAL + layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { + setMargins(0, 0, dpToPx(layout.context, 2), dpToPx(layout.context, 2)) + } + setBackgroundColor(layout.context.getColor(R.color.mdtp_line_dark)) } + for (e in mElements) { + e.addToLayout(elementLayout) + } + layout.addView(elementLayout) + } + + fun dpToPx(context: Context, dp: Int): Int { + val scale = context.resources.displayMetrics.density + return (dp * scale + 0.5f).toInt() } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/StaticLabel.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/StaticLabel.kt index 96320c2cd1..6510457264 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/StaticLabel.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/StaticLabel.kt @@ -4,10 +4,8 @@ import android.graphics.Typeface import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView -import dagger.android.HasAndroidInjector import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger import info.nightscout.androidaps.utils.resources.ResourceHelper -import javax.inject.Inject class StaticLabel(private val resourceHelper: ResourceHelper) : Element() { @@ -25,24 +23,25 @@ class StaticLabel(private val resourceHelper: ResourceHelper) : Element() { } override fun addToLayout(root: LinearLayout) { - val headerLayout = LinearLayout(root.context) - headerLayout.orientation = LinearLayout.HORIZONTAL - headerLayout.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - headerLayout.setBackgroundColor(resourceHelper.gc(android.R.color.black)) - // text val px = resourceHelper.dpToPx(10) - val textView = TextView(root.context) - textView.text = label - val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) - params.weight = 1.0f - textView.layoutParams = params - textView.setPadding(px, px, px, px) - textView.setTypeface(textView.typeface, Typeface.BOLD) - headerLayout.addView(textView) - trigger?.let { - headerLayout.addView(it.createDeleteButton(root.context, it)) - headerLayout.addView(it.createCloneButton(root.context, it)) - } - root.addView(headerLayout) + root.addView( + LinearLayout(root.context).apply { + orientation = LinearLayout.HORIZONTAL + layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + setBackgroundColor(resourceHelper.gc(android.R.color.black)) + addView( + TextView(root.context).apply { + text = label + layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply { + weight = 1.0f + } + setPadding(px, px, px, px) + setTypeface(typeface, Typeface.BOLD) + }) + trigger?.let { + addView(it.createDeleteButton(root.context, it)) + addView(it.createCloneButton(root.context, it)) + } + }) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.kt index f9b67a74de..4ba39c7461 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.kt @@ -1,6 +1,6 @@ package info.nightscout.androidaps.plugins.general.automation.events import info.nightscout.androidaps.events.Event -import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector -class EventAutomationUpdateTrigger(val trigger: Trigger) : Event() +class EventAutomationUpdateTrigger(val trigger: TriggerConnector) : Event() diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt index b48bf5eecd..fd9e7295c4 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.kt @@ -56,7 +56,7 @@ abstract class Trigger(val injector: HasAndroidInjector) { abstract fun icon(): Optional abstract fun duplicate(): Trigger - private fun scanForActivity(cont: Context?): AppCompatActivity? { + fun scanForActivity(cont: Context?): AppCompatActivity? { return when (cont) { null -> null is AppCompatActivity -> cont @@ -84,27 +84,19 @@ abstract class Trigger(val injector: HasAndroidInjector) { //return (clazz.primaryConstructor?.call(injector) as Trigger).fromJSON(data?.toString() ?: "") return when (type) { TriggerAutosensValue::class.java.name, // backward compatibility - TriggerAutosensValue::class.java.simpleName -> TriggerAutosensValue(injector).fromJSON( - data.toString() - ) + TriggerAutosensValue::class.java.simpleName -> TriggerAutosensValue(injector).fromJSON(data.toString()) TriggerBg::class.java.name, TriggerBg::class.java.simpleName -> TriggerBg(injector).fromJSON(data.toString()) TriggerBolusAgo::class.java.name, - TriggerBolusAgo::class.java.simpleName -> TriggerBolusAgo(injector).fromJSON( - data.toString() - ) + TriggerBolusAgo::class.java.simpleName -> TriggerBolusAgo(injector).fromJSON(data.toString()) TriggerBTDevice::class.java.name, - TriggerBTDevice::class.java.simpleName -> TriggerBTDevice(injector).fromJSON( - data.toString() - ) + TriggerBTDevice::class.java.simpleName -> TriggerBTDevice(injector).fromJSON(data.toString()) TriggerIob::class.java.name, TriggerIob::class.java.simpleName -> TriggerIob(injector).fromJSON(data.toString()) TriggerCOB::class.java.name, TriggerCOB::class.java.simpleName -> TriggerCOB(injector).fromJSON(data.toString()) TriggerConnector::class.java.name, - TriggerConnector::class.java.simpleName -> TriggerConnector(injector).fromJSON( - data.toString() - ) + TriggerConnector::class.java.simpleName -> TriggerConnector(injector).fromJSON(data.toString()) TriggerDelta::class.java.name, TriggerDelta::class.java.simpleName -> TriggerDelta(injector).fromJSON(data.toString()) TriggerDummy::class.java.name, @@ -112,100 +104,73 @@ abstract class Trigger(val injector: HasAndroidInjector) { TriggerIob::class.java.name, TriggerIob::class.java.simpleName -> TriggerIob(injector).fromJSON(data.toString()) TriggerLocation::class.java.name, - TriggerLocation::class.java.simpleName -> TriggerLocation(injector).fromJSON( - data.toString() - ) + TriggerLocation::class.java.simpleName -> TriggerLocation(injector).fromJSON(data.toString()) TriggerProfilePercent::class.java.name, - TriggerProfilePercent::class.java.simpleName -> TriggerProfilePercent(injector).fromJSON( - data.toString() - ) + TriggerProfilePercent::class.java.simpleName -> TriggerProfilePercent(injector).fromJSON(data.toString()) TriggerPumpLastConnection::class.java.name, - TriggerPumpLastConnection::class.java.simpleName -> TriggerPumpLastConnection(injector).fromJSON( - data.toString() - ) + TriggerPumpLastConnection::class.java.simpleName -> TriggerPumpLastConnection(injector).fromJSON(data.toString()) TriggerRecurringTime::class.java.name, - TriggerRecurringTime::class.java.simpleName -> TriggerRecurringTime(injector).fromJSON( - data.toString() - ) + TriggerRecurringTime::class.java.simpleName -> TriggerRecurringTime(injector).fromJSON(data.toString()) TriggerTempTarget::class.java.name, - TriggerTempTarget::class.java.simpleName -> TriggerTempTarget(injector).fromJSON( - data.toString() - ) + TriggerTempTarget::class.java.simpleName -> TriggerTempTarget(injector).fromJSON(data.toString()) TriggerTempTargetValue::class.java.name, - TriggerTempTargetValue::class.java.simpleName -> TriggerTempTargetValue(injector).fromJSON( - data.toString() - ) + TriggerTempTargetValue::class.java.simpleName -> TriggerTempTargetValue(injector).fromJSON(data.toString()) TriggerTime::class.java.name, TriggerTime::class.java.simpleName -> TriggerTime(injector).fromJSON(data.toString()) TriggerTimeRange::class.java.name, - TriggerTimeRange::class.java.simpleName -> TriggerTimeRange(injector).fromJSON( - data.toString() - ) + TriggerTimeRange::class.java.simpleName -> TriggerTimeRange(injector).fromJSON(data.toString()) TriggerWifiSsid::class.java.name, - TriggerWifiSsid::class.java.simpleName -> TriggerWifiSsid(injector).fromJSON( - data.toString() - ) + TriggerWifiSsid::class.java.simpleName -> TriggerWifiSsid(injector).fromJSON(data.toString()) else -> TriggerConnector(injector) } } - fun createAddButton(context: Context, trigger: TriggerConnector): ImageButton { + fun createAddButton(context: Context, trigger: TriggerConnector): ImageButton = // Button [+] - val buttonAdd = ImageButton(context) - val params = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - params.gravity = Gravity.CENTER - buttonAdd.layoutParams = params - buttonAdd.setImageResource(R.drawable.ic_add) - buttonAdd.contentDescription = resourceHelper.gs(R.string.add_short) - buttonAdd.setOnClickListener { - scanForActivity(context)?.supportFragmentManager?.let { - val dialog = ChooseTriggerDialog() - dialog.show(it, "ChooseTriggerDialog") - dialog.setOnClickListener(object : ChooseTriggerDialog.OnClickListener { - override fun onClick(newTriggerObject: Trigger) { - trigger.list.add(newTriggerObject) - rxBus.send(EventTriggerChanged()) - } - }) + ImageButton(context).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + gravity = Gravity.CENTER + } + setImageResource(R.drawable.ic_add) + contentDescription = resourceHelper.gs(R.string.add_short) + setOnClickListener { + scanForActivity(context)?.supportFragmentManager?.let { + val dialog = ChooseTriggerDialog() + dialog.show(it, "ChooseTriggerDialog") + dialog.setOnClickListener(object : ChooseTriggerDialog.OnClickListener { + override fun onClick(newTriggerObject: Trigger) { + trigger.list.add(newTriggerObject) + rxBus.send(EventTriggerChanged()) + } + }) + } } } - return buttonAdd - } - fun createDeleteButton(context: Context, trigger: Trigger): ImageButton { + fun createDeleteButton(context: Context, trigger: Trigger): ImageButton = // Button [-] - val buttonRemove = ImageButton(context) - val params = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - params.gravity = Gravity.CENTER - buttonRemove.layoutParams = params - buttonRemove.setImageResource(R.drawable.ic_remove) - buttonRemove.contentDescription = resourceHelper.gs(R.string.delete_short) - buttonRemove.setOnClickListener { - rxBus.send(EventTriggerRemove(trigger)) + ImageButton(context).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + gravity = Gravity.CENTER + } + setImageResource(R.drawable.ic_remove) + contentDescription = resourceHelper.gs(R.string.delete_short) + setOnClickListener { + rxBus.send(EventTriggerRemove(trigger)) + } } - return buttonRemove - } - fun createCloneButton(context: Context, trigger: Trigger): ImageButton { + fun createCloneButton(context: Context, trigger: Trigger): ImageButton = // Button [*] - val buttonClone = ImageButton(context) - val params = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - params.gravity = Gravity.CENTER - buttonClone.layoutParams = params - buttonClone.setImageResource(R.drawable.ic_clone) - buttonClone.contentDescription = resourceHelper.gs(R.string.copy_short) - buttonClone.setOnClickListener { - rxBus.send(EventTriggerClone(trigger)) + ImageButton(context).apply { + val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply { + gravity = Gravity.CENTER + } + layoutParams = params + setImageResource(R.drawable.ic_clone) + contentDescription = resourceHelper.gs(R.string.copy_short) + setOnClickListener { + rxBus.send(EventTriggerClone(trigger)) + } } - return buttonClone - } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt index b7b47aa66f..74f3b77648 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgo.kt @@ -4,6 +4,7 @@ import android.widget.LinearLayout import com.google.common.base.Optional import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R +import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.general.automation.elements.Comparator @@ -36,7 +37,8 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) { } override fun shouldRun(): Boolean { - val lastBolusTime = repository.getLastBolusRecordOfType(Bolus.Type.NORMAL)?.timestamp ?: 0L + val lastBolus = repository.getLastBolusRecordOfTypeWrapped(Bolus.Type.NORMAL).blockingGet() + val lastBolusTime = if (lastBolus is ValueWrapper.Existing) lastBolus.value.timestamp else 0L if (lastBolusTime == 0L) return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) { aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) @@ -81,7 +83,7 @@ class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) { LayoutBuilder() .add(StaticLabel(resourceHelper, R.string.lastboluslabel, this)) .add(comparator) - .add(LabelWithElement(resourceHelper, resourceHelper.gs(R.string.lastboluslabel) + ": ", "", minutesAgo)) + .add(LabelWithElement(resourceHelper, resourceHelper.gs(R.string.lastboluslabel) + ": ", resourceHelper.gs(R.string.unit_minutes), minutesAgo)) .build(root) } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt index 91311a84da..8a4c667d85 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.kt @@ -1,19 +1,20 @@ package info.nightscout.androidaps.plugins.general.automation.triggers import android.content.Context -import android.view.View +import android.graphics.Typeface +import android.view.Gravity import android.view.ViewGroup -import android.widget.AdapterView -import android.widget.ArrayAdapter import android.widget.LinearLayout -import android.widget.Spinner +import android.widget.TextView import androidx.annotation.StringRes import com.google.common.base.Optional import dagger.android.HasAndroidInjector import info.nightscout.androidaps.automation.R import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseOperationDialog import info.nightscout.androidaps.utils.JsonHelper.safeGetString import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.ui.VerticalTextView import org.json.JSONArray import org.json.JSONObject import java.util.* @@ -35,7 +36,7 @@ class TriggerConnector(injector: HasAndroidInjector) : Trigger(injector) { @get:StringRes val stringRes: Int get() = when (this) { - OR -> R.string.or + OR -> R.string.or XOR -> R.string.xor AND -> R.string.and } @@ -119,51 +120,75 @@ class TriggerConnector(injector: HasAndroidInjector) : Trigger(injector) { override fun duplicate(): Trigger = TriggerConnector(injector, connectorType) override fun generateDialog(root: LinearLayout) { - val padding = resourceHelper.dpToPx(5) - root.setPadding(padding, padding, padding, padding) - root.setBackgroundResource(R.drawable.border_automation_unit) - // Header with spinner - val headerLayout = LinearLayout(root.context) - headerLayout.orientation = LinearLayout.HORIZONTAL - headerLayout.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - headerLayout.addView(createSpinner(root.context)) - headerLayout.addView(createAddButton(root.context, this)) - headerLayout.addView(createDeleteButton(root.context, this)) - root.addView(headerLayout) - // Child triggers - val listLayout = LinearLayout(root.context) - listLayout.orientation = LinearLayout.VERTICAL - listLayout.setBackgroundColor(resourceHelper.gc(R.color.mdtp_line_dark)) - //listLayout.setPadding(resourceHelper.dpToPx(5), resourceHelper.dpToPx(5), resourceHelper.dpToPx(5), 0) - val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - params.setMargins(resourceHelper.dpToPx(15), 0, resourceHelper.dpToPx(5), resourceHelper.dpToPx(4)) - listLayout.layoutParams = params - for (t in list) t.generateDialog(listLayout) - root.addView(listLayout) - } - - private fun createSpinner(context: Context): Spinner { - val initialPosition = connectorType.ordinal - val spinner = Spinner(context) - val spinnerArrayAdapter = ArrayAdapter(context, R.layout.spinner_centered, Type.labels(resourceHelper)) - spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = spinnerArrayAdapter - spinner.setSelection(initialPosition) - spinner.setBackgroundColor(resourceHelper.gc(R.color.black_overlay)) - val params = LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT - ) - params.setMargins(0, resourceHelper.dpToPx(8), 0, resourceHelper.dpToPx(8)) - params.weight = 1.0f - spinner.layoutParams = params - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - setType(Type.values()[position]) - } - - override fun onNothingSelected(parent: AdapterView<*>?) {} + val mainLayout = LinearLayout(root.context).also { + it.orientation = LinearLayout.HORIZONTAL + it.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } - return spinner + val padding = resourceHelper.dpToPx(3) + mainLayout.setPadding(padding, padding, padding, padding) + mainLayout.setBackgroundResource(R.drawable.border_automation_unit) + + val buttonLayout = LinearLayout(root.context).also { + it.orientation = LinearLayout.HORIZONTAL + it.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + } + buttonLayout.addView(createAddButton(root.context, this)) + buttonLayout.addView(createDeleteButton(root.context, this)) + + val rightSideLayout = LinearLayout(root.context).also { + it.orientation = LinearLayout.VERTICAL + it.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) + } + + rightSideLayout.addView(buttonLayout) + + // Child triggers + val listLayout = LinearLayout(root.context).also { + it.orientation = LinearLayout.VERTICAL + it.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).also { params -> + params.setMargins(resourceHelper.dpToPx(1), 0, resourceHelper.dpToPx(1), resourceHelper.dpToPx(2)) + } + } + for (t in list) { + t.generateDialog(listLayout) + listLayout.addView( + TextView(root.context).also { + it.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + it.setPadding(0, resourceHelper.dpToPx(0.3f), 0, 0) + }) + } + rightSideLayout.addView(listLayout) + + // Header with spinner + mainLayout.addView(createVerticalView(root.context)) + mainLayout.addView(rightSideLayout) + root.addView(mainLayout) } + + private fun createVerticalView(context: Context): VerticalTextView = + VerticalTextView(context).apply { + text = resourceHelper.gs(connectorType.stringRes) + gravity = gravity or Gravity.CENTER_VERTICAL + setTypeface(typeface, Typeface.BOLD) + setBackgroundColor(resourceHelper.gc(R.color.black_overlay)) + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT).also { ll -> + ll.setMargins(resourceHelper.dpToPx(3), resourceHelper.dpToPx(3), resourceHelper.dpToPx(3), resourceHelper.dpToPx(3)) + } + setOnClickListener { + scanForActivity(context)?.supportFragmentManager?.let { + ChooseOperationDialog().also { dialog -> + dialog.setCallback(object : ChooseOperationDialog.Callback() { + override fun run() { + result?.let { result -> + setType(Type.values()[result]) + text = resourceHelper.gs(connectorType.stringRes) + } + } + }) + dialog.setCheckedIndex(connectorType.ordinal) + dialog.show(it, "TriggerConnector") + } + } + } + } } \ No newline at end of file diff --git a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt index 2145546a7c..d03022cc18 100644 --- a/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt +++ b/automation/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.kt @@ -55,6 +55,12 @@ class TriggerProfilePercent(injector: HasAndroidInjector) : Trigger(injector) { return true } } + if (profile is ProfileSealed.Pure) { + if (comparator.value.check(100.0, pct.value)) { + aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) + return true + } + } aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription()) return false } diff --git a/automation/src/main/res/layout/automation_dialog_choose_operation.xml b/automation/src/main/res/layout/automation_dialog_choose_operation.xml new file mode 100644 index 0000000000..6f380dfbda --- /dev/null +++ b/automation/src/main/res/layout/automation_dialog_choose_operation.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/automation/src/main/res/layout/automation_dialog_edit_trigger.xml b/automation/src/main/res/layout/automation_dialog_edit_trigger.xml index 45fb0e3a53..bb019f1ef3 100644 --- a/automation/src/main/res/layout/automation_dialog_edit_trigger.xml +++ b/automation/src/main/res/layout/automation_dialog_edit_trigger.xml @@ -7,7 +7,7 @@ android:focusableInTouchMode="true" android:minWidth="300dp" android:orientation="vertical" - tools:context=".plugins.general.automation.dialogs.EditEventDialog"> + tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog"> diff --git a/automation/src/main/res/layout/automation_dialog_event.xml b/automation/src/main/res/layout/automation_dialog_event.xml index 68fc935634..d40056549e 100644 --- a/automation/src/main/res/layout/automation_dialog_event.xml +++ b/automation/src/main/res/layout/automation_dialog_event.xml @@ -7,14 +7,14 @@ android:focusableInTouchMode="true" android:minWidth="300dp" android:orientation="vertical" - tools:context=".plugins.general.automation.dialogs.EditEventDialog"> + tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog"> - - + + + + + + + + + + + EDIT Choose an action type Choose a trigger type + Choose a operation type Triggers: REMOVE Preconditions: Automation event Reorder automation_settings - + User action \ No newline at end of file diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt index 31993e3fa1..f5d2da28b8 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/AutomationEventTest.kt @@ -8,6 +8,7 @@ import info.nightscout.androidaps.interfaces.Loop import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.automation.actions.Action import info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopEnable +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnectorTest import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy import info.nightscout.androidaps.utils.resources.ResourceHelper @@ -44,11 +45,12 @@ class AutomationEventTest : TestBase() { // create test object val event = AutomationEvent(injector) event.title = "Test" - event.trigger = TriggerDummy(injector).instantiate(JSONObject(TriggerConnectorTest.oneItem)) + event.trigger = TriggerDummy(injector).instantiate(JSONObject(TriggerConnectorTest.oneItem)) as TriggerConnector event.addAction(ActionLoopEnable(injector)) // export to json - val eventJsonExpected = "{\"autoRemove\":false,\"readOnly\":false,\"trigger\":\"{\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"data\\\\\\\":{\\\\\\\"connectorType\\\\\\\":\\\\\\\"AND\\\\\\\",\\\\\\\"triggerList\\\\\\\":[]},\\\\\\\"type\\\\\\\":\\\\\\\"TriggerConnector\\\\\\\"}\\\"]},\\\"type\\\":\\\"TriggerConnector\\\"}\",\"title\":\"Test\",\"systemAction\":false,\"actions\":[\"{\\\"type\\\":\\\"ActionLoopEnable\\\"}\"],\"enabled\":true}" + val eventJsonExpected = + "{\"userAction\":false,\"autoRemove\":false,\"readOnly\":false,\"trigger\":\"{\\\"data\\\":{\\\"connectorType\\\":\\\"AND\\\",\\\"triggerList\\\":[\\\"{\\\\\\\"data\\\\\\\":{\\\\\\\"connectorType\\\\\\\":\\\\\\\"AND\\\\\\\",\\\\\\\"triggerList\\\\\\\":[]},\\\\\\\"type\\\\\\\":\\\\\\\"TriggerConnector\\\\\\\"}\\\"]},\\\"type\\\":\\\"TriggerConnector\\\"}\",\"title\":\"Test\",\"systemAction\":false,\"actions\":[\"{\\\"type\\\":\\\"ActionLoopEnable\\\"}\"],\"enabled\":true}" Assert.assertEquals(eventJsonExpected, event.toJSON()) // clone diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt index 11d2b392c6..d9a6ad0509 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBolusAgoTest.kt @@ -2,8 +2,10 @@ package info.nightscout.androidaps.plugins.general.automation.triggers import com.google.common.base.Optional import info.nightscout.androidaps.automation.R +import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.plugins.general.automation.elements.Comparator +import io.reactivex.Single import org.json.JSONException import org.json.JSONObject import org.junit.Assert @@ -22,13 +24,18 @@ class TriggerBolusAgoTest : TriggerTestBase() { @Test fun shouldRunTest() { - `when`(repository.getLastBolusRecordOfType(Bolus.Type.NORMAL)).thenReturn( - Bolus( - timestamp = now, - amount = 0.0, - type = Bolus.Type.NORMAL + // Set last bolus time to now + `when`(repository.getLastBolusRecordOfTypeWrapped(Bolus.Type.NORMAL)).thenReturn( + Single.just( + ValueWrapper.Existing( + Bolus( + timestamp = now, + amount = 0.0, + type = Bolus.Type.NORMAL + ) + ) ) - ) // Set last bolus time to now + ) `when`(dateUtil.now()).thenReturn(now + 10 * 60 * 1000) // set current time to now + 10 min var t = TriggerBolusAgo(injector).setValue(110).comparator(Comparator.Compare.IS_EQUAL) Assert.assertEquals(110, t.minutesAgo.value) @@ -51,13 +58,18 @@ class TriggerBolusAgoTest : TriggerTestBase() { Assert.assertTrue(t.shouldRun()) t = TriggerBolusAgo(injector).setValue(390).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER) Assert.assertTrue(t.shouldRun()) - `when`(repository.getLastBolusRecordOfType(Bolus.Type.NORMAL)).thenReturn( - Bolus( - timestamp = 0L, - amount = 0.0, - type = Bolus.Type.NORMAL + // Set last bolus time to 0 + `when`(repository.getLastBolusRecordOfTypeWrapped(Bolus.Type.NORMAL)).thenReturn( + Single.just( + ValueWrapper.Existing( + Bolus( + timestamp = 0, + amount = 0.0, + type = Bolus.Type.NORMAL + ) + ) ) - ) // Set last bolus time to 0 + ) t = TriggerBolusAgo(injector).comparator(Comparator.Compare.IS_NOT_AVAILABLE) Assert.assertTrue(t.shouldRun()) } diff --git a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt index d1343adf6c..75d3e24238 100644 --- a/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt +++ b/automation/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercentTest.kt @@ -53,7 +53,7 @@ class TriggerProfilePercentTest : TriggerTestBase() { Assert.assertEquals(bgJson, t.toJSON()) } - @Test @Throws(JSONException::class) fun fromJSONTest() { + @Test fun fromJSONTest() { val t: TriggerProfilePercent = TriggerProfilePercent(injector).setValue(120.0).comparator(Comparator.Compare.IS_EQUAL) val t2 = TriggerDummy(injector).instantiate(JSONObject(t.toJSON())) as TriggerProfilePercent Assert.assertEquals(Comparator.Compare.IS_EQUAL, t2.comparator.value) diff --git a/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt b/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt index 4182538781..520b293238 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/alertDialogs/OKDialog.kt @@ -14,11 +14,11 @@ object OKDialog { @SuppressLint("InflateParams") fun show(context: Context, title: String, message: String, runnable: Runnable? = null) { var okClicked = false - var notEmptytitle = title - if (notEmptytitle.isEmpty()) notEmptytitle = context.getString(R.string.message) + var notEmptyTitle = title + if (notEmptyTitle.isEmpty()) notEmptyTitle = context.getString(R.string.message) AlertDialogHelper.Builder(context) - .setCustomTitle(AlertDialogHelper.buildCustomTitle(context, notEmptytitle)) + .setCustomTitle(AlertDialogHelper.buildCustomTitle(context, notEmptyTitle)) .setMessage(message) .setPositiveButton(context.getString(R.string.ok)) { dialog: DialogInterface, _: Int -> if (okClicked) return@setPositiveButton @@ -36,11 +36,11 @@ object OKDialog { @SuppressLint("InflateParams") fun show(activity: FragmentActivity, title: String, message: Spanned, runnable: Runnable? = null) { var okClicked = false - var notEmptytitle = title - if (notEmptytitle.isEmpty()) notEmptytitle = activity.getString(R.string.message) + var notEmptyTitle = title + if (notEmptyTitle.isEmpty()) notEmptyTitle = activity.getString(R.string.message) AlertDialogHelper.Builder(activity) - .setCustomTitle(AlertDialogHelper.buildCustomTitle(activity, notEmptytitle)) + .setCustomTitle(AlertDialogHelper.buildCustomTitle(activity, notEmptyTitle)) .setMessage(message) .setPositiveButton(activity.getString(R.string.ok)) { dialog: DialogInterface, _: Int -> if (okClicked) return@setPositiveButton diff --git a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt index 7a068c57ee..8f6379d657 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt @@ -21,5 +21,6 @@ interface ResourceHelper { fun decodeResource(id : Int) : Bitmap fun getDisplayMetrics(): DisplayMetrics fun dpToPx(dp: Int): Int + fun dpToPx(dp: Float): Int fun shortTextMode(): Boolean } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt index 214ccc8b53..c05693684d 100644 --- a/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt +++ b/core/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt @@ -26,7 +26,7 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont override fun gq(@PluralsRes id: Int, quantity: Int, vararg args: Any?): String = context.resources.getQuantityString(id, quantity, *args) - override fun gsNotLocalised(@StringRes id: Int, vararg args: Any?) : String = + override fun gsNotLocalised(@StringRes id: Int, vararg args: Any?): String = with(Configuration(context.resources.configuration)) { setLocale(Locale.ENGLISH) context.createConfigurationContext(this).getString(id, args) @@ -51,7 +51,7 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont override fun decodeResource(id: Int): Bitmap = BitmapFactory.decodeResource(context.resources, id) - override fun getDisplayMetrics():DisplayMetrics = + override fun getDisplayMetrics(): DisplayMetrics = context.resources.displayMetrics override fun dpToPx(dp: Int): Int { @@ -59,5 +59,10 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont return (dp * scale + 0.5f).toInt() } - override fun shortTextMode() : Boolean = !gb(R.bool.isTablet) + override fun dpToPx(dp: Float): Int { + val scale = context.resources.displayMetrics.density + return (dp * scale + 0.5f).toInt() + } + + override fun shortTextMode(): Boolean = !gb(R.bool.isTablet) } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/utils/ui/VerticalTextView.kt b/core/src/main/java/info/nightscout/androidaps/utils/ui/VerticalTextView.kt new file mode 100644 index 0000000000..b771b4073c --- /dev/null +++ b/core/src/main/java/info/nightscout/androidaps/utils/ui/VerticalTextView.kt @@ -0,0 +1,44 @@ +package info.nightscout.androidaps.utils.ui + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import android.view.Gravity +import androidx.appcompat.widget.AppCompatTextView + +class VerticalTextView(context: Context, attrs: AttributeSet? = null) : AppCompatTextView(context, attrs) { + + private var topDown = false + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(heightMeasureSpec, widthMeasureSpec) + setMeasuredDimension(measuredHeight, measuredWidth) + } + + override fun onDraw(canvas: Canvas) { + val textPaint = paint + textPaint.color = currentTextColor + textPaint.drawableState = drawableState + canvas.save() + if (topDown) { + canvas.translate(width.toFloat(), 0f) + canvas.rotate(90f) + } else { + canvas.translate(0f, height.toFloat()) + canvas.rotate(-90f) + } + canvas.translate(compoundPaddingLeft.toFloat(), extendedPaddingTop.toFloat()) + layout.draw(canvas) + canvas.restore() + } + + init { + val gravity = gravity + topDown = if (Gravity.isVertical(gravity) && gravity and Gravity.VERTICAL_GRAVITY_MASK == Gravity.BOTTOM) { + setGravity(gravity and Gravity.HORIZONTAL_GRAVITY_MASK or Gravity.TOP) + false + } else { + true + } + } +} \ No newline at end of file diff --git a/core/src/main/res/layout/dialog_alert_custom.xml b/core/src/main/res/layout/dialog_alert_custom.xml index c7818b902a..3c2df5b99b 100644 --- a/core/src/main/res/layout/dialog_alert_custom.xml +++ b/core/src/main/res/layout/dialog_alert_custom.xml @@ -3,6 +3,7 @@ Please use AlertDialogHelper or wrap inflater context with ContextThemeWrapper(context, R.style.AppTheme) --> @@ -19,7 +20,7 @@ android:id="@+id/alertdialog_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:tint="?dialogTitleIconTint" /> + app:tint="?dialogTitleIconTint" /> #121212 #66000000 + #424242 + #B3FFFFFF + #505050 diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt index f7ec1c98ab..f32c0aac0f 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -436,8 +436,10 @@ import kotlin.math.roundToInt .subscribeOn(Schedulers.io()) .toWrappedSingle() - fun getLastBolusRecordOfType(type: Bolus.Type): Bolus? = + fun getLastBolusRecordOfTypeWrapped(type: Bolus.Type): Single> = database.bolusDao.getLastBolusRecordOfType(type) + .subscribeOn(Schedulers.io()) + .toWrappedSingle() fun getOldestBolusRecord(): Bolus? = database.bolusDao.getOldestBolusRecord() diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt index 7bfa7fd72a..f69fd5257d 100644 --- a/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt @@ -3,10 +3,8 @@ package info.nightscout.androidaps.database.daos import androidx.room.Dao import androidx.room.Query import info.nightscout.androidaps.database.TABLE_BOLUSES -import info.nightscout.androidaps.database.TABLE_BOLUS_CALCULATOR_RESULTS import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.entities.Bolus -import info.nightscout.androidaps.database.entities.BolusCalculatorResult import io.reactivex.Maybe import io.reactivex.Single @@ -42,7 +40,7 @@ internal interface BolusDao : TraceableDao { fun getLastBolusRecordMaybe(exclude: Bolus.Type = Bolus.Type.PRIMING): Maybe @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND type == :only AND referenceId IS NULL ORDER BY timestamp DESC LIMIT 1") - fun getLastBolusRecordOfType(only: Bolus.Type): Bolus? + fun getLastBolusRecordOfType(only: Bolus.Type): Maybe @Query("SELECT * FROM $TABLE_BOLUSES WHERE isValid = 1 AND type <> :exclude AND referenceId IS NULL ORDER BY timestamp ASC LIMIT 1") fun getOldestBolusRecord(exclude: Bolus.Type = Bolus.Type.PRIMING): Bolus?