Improve SetupWizard, allow Tidepool for passing first Objective

This commit is contained in:
Milos Kozak 2023-02-14 20:18:27 +01:00
parent 5abaf4e1ca
commit 780d9261f5
14 changed files with 563 additions and 536 deletions

View file

@ -1,16 +1,59 @@
package info.nightscout.interfaces package info.nightscout.interfaces
import android.widget.LinearLayout
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
interface ConfigBuilder { interface ConfigBuilder {
/**
* Called during start of app to load configuration and start enabled plugins
*/
fun initialize() fun initialize()
/**
* Store current configuration to SharedPreferences
*/
fun storeSettings(from: String) fun storeSettings(from: String)
/**
* Enable another plugin and fragment and disable currently enabled if they are mutually exclusive
*/
fun performPluginSwitch(changedPlugin: PluginBase, enabled: Boolean, type: PluginType) fun performPluginSwitch(changedPlugin: PluginBase, enabled: Boolean, type: PluginType)
/** /**
* Make sure plugins configuration is valid after enabling/disabling plugin * Make sure plugins configuration is valid after enabling/disabling plugin
*/ */
fun processOnEnabledCategoryChanged(changedPlugin: PluginBase, type: PluginType) fun processOnEnabledCategoryChanged(changedPlugin: PluginBase, type: PluginType)
/**
* Fill LinearLayout with list of available plugins and checkboxes for enabling/disabling
*
* @param title Paragraph title or null if provided elsewhere
* @param description comment
* @param pluginType plugin category for example SYNC
* @param plugins list of plugins
* @param pluginViewHolders links to created UI elements (for calling `update` if configuration is changed)
* @param fragment
* @param activity either fragment or activity must be non null
* @param parent UI container to add views
*/
fun createViewsForPlugins(
@StringRes title: Int?,
@StringRes description: Int,
pluginType: PluginType,
plugins: List<PluginBase>,
pluginViewHolders: ArrayList<PluginViewHolderInterface>,
fragment: Fragment? = null,
activity: FragmentActivity? = null,
parent: LinearLayout
)
interface PluginViewHolderInterface {
fun update()
}
} }

View file

@ -0,0 +1,3 @@
package info.nightscout.interfaces.sync
interface Tidepool : Sync

View file

@ -165,7 +165,7 @@
<string name="isf_short">ISF</string> <string name="isf_short">ISF</string>
<string name="canceling_tbr_failed">Canceling of temporary basal failed</string> <string name="canceling_tbr_failed">Canceling of temporary basal failed</string>
<string name="canceling_eb_failed">Canceling of extended bolus failed</string> <string name="canceling_eb_failed">Canceling of extended bolus failed</string>
<string name="virtualpump_uploadstatus_title">Upload status to NS</string> <string name="virtualpump_uploadstatus_title">Upload status to NS or Tidepool</string>
<string name="suspendloop_label">Disabled/Suspended loop</string> <string name="suspendloop_label">Disabled/Suspended loop</string>
<string name="iob_label">Insulin on Board (IOB)</string> <string name="iob_label">Insulin on Board (IOB)</string>

View file

@ -1,36 +1,24 @@
package info.nightscout.configuration.configBuilder package info.nightscout.configuration.configBuilder
import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.TextView
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.configuration.R import info.nightscout.configuration.R
import info.nightscout.configuration.configBuilder.events.EventConfigBuilderUpdateGui import info.nightscout.configuration.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.configuration.databinding.ConfigbuilderFragmentBinding import info.nightscout.configuration.databinding.ConfigbuilderFragmentBinding
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.protection.ProtectionCheck import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.protection.ProtectionCheck.Protection.PREFERENCES import info.nightscout.interfaces.protection.ProtectionCheck.Protection.PREFERENCES
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventRebuildTabs
import info.nightscout.shared.extensions.toVisibility import info.nightscout.shared.extensions.toVisibility
import info.nightscout.shared.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject import javax.inject.Inject
@ -39,17 +27,15 @@ class ConfigBuilderFragment : DaggerFragment() {
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var rh: ResourceHelper @Inject lateinit var configBuilder: ConfigBuilder
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var ctx: Context
@Inject lateinit var uiInteraction: UiInteraction @Inject lateinit var uiInteraction: UiInteraction
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private val pluginViewHolders = ArrayList<PluginViewHolder>() private val pluginViewHolders = ArrayList<ConfigBuilder.PluginViewHolderInterface>()
private var inMenu = false private var inMenu = false
private var queryingProtection = false private var queryingProtection = false
private var _binding: ConfigbuilderFragmentBinding? = null private var _binding: ConfigbuilderFragmentBinding? = null
@ -98,119 +84,111 @@ class ConfigBuilderFragment : DaggerFragment() {
@Synchronized @Synchronized
private fun updateGUI() { private fun updateGUI() {
binding.categories.removeAllViews() binding.categories.removeAllViews()
createViewsForPlugins(R.string.configbuilder_profile, R.string.configbuilder_profile_description, PluginType.PROFILE, activePlugin.getSpecificPluginsVisibleInList(PluginType.PROFILE)) configBuilder.createViewsForPlugins(
title = R.string.configbuilder_profile,
description = R.string.configbuilder_profile_description,
pluginType = PluginType.PROFILE,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.PROFILE),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
if (config.APS || config.PUMPCONTROL || config.isEngineeringMode()) if (config.APS || config.PUMPCONTROL || config.isEngineeringMode())
createViewsForPlugins(info.nightscout.core.ui.R.string.configbuilder_insulin, R.string.configbuilder_insulin_description, PluginType.INSULIN, activePlugin.getSpecificPluginsVisibleInList(PluginType.INSULIN)) configBuilder.createViewsForPlugins(
title = info.nightscout.core.ui.R.string.configbuilder_insulin,
description = R.string.configbuilder_insulin_description,
pluginType = PluginType.INSULIN,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.INSULIN),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
if (!config.NSCLIENT) { if (!config.NSCLIENT) {
createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, activePlugin.getSpecificPluginsVisibleInList(PluginType.BGSOURCE)) configBuilder.createViewsForPlugins(
createViewsForPlugins(R.string.configbuilder_smoothing, R.string.configbuilder_smoothing_description, PluginType.SMOOTHING, activePlugin.getSpecificPluginsVisibleInList(PluginType.SMOOTHING)) title = R.string.configbuilder_bgsource,
createViewsForPlugins(R.string.configbuilder_pump, R.string.configbuilder_pump_description, PluginType.PUMP, activePlugin.getSpecificPluginsVisibleInList(PluginType.PUMP)) description = R.string.configbuilder_bgsource_description,
pluginType = PluginType.BGSOURCE,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.BGSOURCE),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
configBuilder.createViewsForPlugins(
title = R.string.configbuilder_smoothing,
description = R.string.configbuilder_smoothing_description,
pluginType = PluginType.SMOOTHING,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.SMOOTHING),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
configBuilder.createViewsForPlugins(
title = R.string.configbuilder_pump,
description = R.string.configbuilder_pump_description,
pluginType = PluginType.PUMP,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.PUMP),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
} }
if (config.APS || config.PUMPCONTROL || config.isEngineeringMode()) if (config.APS || config.PUMPCONTROL || config.isEngineeringMode())
createViewsForPlugins(R.string.configbuilder_sensitivity, R.string.configbuilder_sensitivity_description, PluginType.SENSITIVITY, activePlugin.getSpecificPluginsVisibleInList(PluginType.SENSITIVITY)) configBuilder.createViewsForPlugins(
title = R.string.configbuilder_sensitivity,
description = R.string.configbuilder_sensitivity_description,
pluginType = PluginType.SENSITIVITY,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.SENSITIVITY),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
if (config.APS) { if (config.APS) {
createViewsForPlugins(R.string.configbuilder_aps, R.string.configbuilder_aps_description, PluginType.APS, activePlugin.getSpecificPluginsVisibleInList(PluginType.APS)) configBuilder.createViewsForPlugins(
createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP)) title = R.string.configbuilder_aps,
createViewsForPlugins(info.nightscout.core.ui.R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS)) description = R.string.configbuilder_aps_description,
} pluginType = PluginType.APS,
createViewsForPlugins(R.string.configbuilder_sync, R.string.configbuilder_sync_description, PluginType.SYNC, activePlugin.getSpecificPluginsVisibleInList(PluginType.SYNC)) plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.APS),
createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, activePlugin.getSpecificPluginsVisibleInList(PluginType.GENERAL)) pluginViewHolders = pluginViewHolders,
} fragment = this,
parent = binding.categories
private fun createViewsForPlugins(@StringRes title: Int, @StringRes description: Int, pluginType: PluginType, plugins: List<PluginBase>) { )
if (plugins.isEmpty()) return configBuilder.createViewsForPlugins(
@Suppress("InflateParams") title = R.string.configbuilder_loop,
val parent = layoutInflater.inflate(R.layout.configbuilder_single_category, null) as LinearLayout description = R.string.configbuilder_loop_description,
(parent.findViewById<View>(R.id.category_title) as TextView).text = rh.gs(title) pluginType = PluginType.LOOP,
(parent.findViewById<View>(R.id.category_description) as TextView).text = rh.gs(description) plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP),
val pluginContainer = parent.findViewById<LinearLayout>(R.id.category_plugins) pluginViewHolders = pluginViewHolders,
for (plugin in plugins) { fragment = this,
val pluginViewHolder = PluginViewHolder(this, pluginType, plugin) parent = binding.categories
pluginContainer.addView(pluginViewHolder.baseView) )
pluginViewHolders.add(pluginViewHolder) configBuilder.createViewsForPlugins(
} title = info.nightscout.core.ui.R.string.constraints,
binding.categories.addView(parent) description = R.string.configbuilder_constraints_description,
} pluginType = PluginType.CONSTRAINTS,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS),
inner class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment, pluginViewHolders = pluginViewHolders,
private val pluginType: PluginType, fragment = this,
private val plugin: PluginBase parent = binding.categories
) { )
@Suppress("InflateParams")
val baseView: LinearLayout = fragment.layoutInflater.inflate(R.layout.configbuilder_single_plugin, null) as LinearLayout
private val enabledExclusive: RadioButton = baseView.findViewById(R.id.plugin_enabled_exclusive)
private val enabledInclusive: CheckBox = baseView.findViewById(R.id.plugin_enabled_inclusive)
private val pluginIcon: ImageView = baseView.findViewById(R.id.plugin_icon)
private val pluginIcon2: ImageView = baseView.findViewById(R.id.plugin_icon2)
private val pluginName: TextView = baseView.findViewById(R.id.plugin_name)
private val pluginDescription: TextView = baseView.findViewById(R.id.plugin_description)
private val pluginPreferences: ImageButton = baseView.findViewById(R.id.plugin_preferences)
private val pluginVisibility: CheckBox = baseView.findViewById(R.id.plugin_visibility)
init {
pluginVisibility.setOnClickListener {
plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked)
configBuilderPlugin.storeSettings("CheckedCheckboxVisible")
rxBus.send(EventRebuildTabs())
configBuilderPlugin.logPluginStatus()
}
enabledExclusive.setOnClickListener {
configBuilderPlugin.switchAllowed(plugin, if (enabledExclusive.visibility == View.VISIBLE) enabledExclusive.isChecked else enabledInclusive.isChecked, fragment.activity, pluginType)
}
enabledInclusive.setOnClickListener {
configBuilderPlugin.switchAllowed(plugin, if (enabledExclusive.visibility == View.VISIBLE) enabledExclusive.isChecked else enabledInclusive.isChecked, fragment.activity, pluginType)
}
pluginPreferences.setOnClickListener {
fragment.activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, {
val i = Intent(ctx, uiInteraction.preferencesActivity)
i.putExtra("id", plugin.preferencesId)
fragment.startActivity(i)
}, null)
}
}
update()
}
fun update() {
enabledExclusive.visibility = areMultipleSelectionsAllowed(pluginType).not().toVisibility()
enabledInclusive.visibility = areMultipleSelectionsAllowed(pluginType).toVisibility()
enabledExclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
enabledExclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
if (plugin.menuIcon != -1) {
pluginIcon.visibility = View.VISIBLE
pluginIcon.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon) })
if (plugin.menuIcon2 != -1) {
pluginIcon2.visibility = View.VISIBLE
pluginIcon2.setImageDrawable(context?.let { ContextCompat.getDrawable(it, plugin.menuIcon2) })
} else {
pluginIcon2.visibility = View.GONE
}
} else {
pluginIcon.visibility = View.GONE
}
pluginName.text = plugin.name
if (plugin.description == null)
pluginDescription.visibility = View.GONE
else {
pluginDescription.visibility = View.VISIBLE
pluginDescription.text = plugin.description
}
pluginPreferences.visibility = if (plugin.preferencesId == -1 || !plugin.isEnabled(pluginType)) View.INVISIBLE else View.VISIBLE
pluginVisibility.visibility = plugin.hasFragment().toVisibility()
pluginVisibility.isEnabled = !(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwaysVisible) && plugin.isEnabled(pluginType)
pluginVisibility.isChecked = plugin.isFragmentVisible()
}
private fun areMultipleSelectionsAllowed(type: PluginType): Boolean {
return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP || type == PluginType.SYNC
} }
configBuilder.createViewsForPlugins(
title = R.string.configbuilder_sync,
description = R.string.configbuilder_sync_description,
pluginType = PluginType.SYNC,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.SYNC),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
configBuilder.createViewsForPlugins(
title = R.string.configbuilder_general,
description = R.string.configbuilder_general_description,
pluginType = PluginType.GENERAL,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.GENERAL),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
} }
private fun updateProtectedUi() { private fun updateProtectedUi() {

View file

@ -1,5 +1,17 @@
package info.nightscout.configuration.configBuilder package info.nightscout.configuration.configBuilder
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.widget.CheckBox
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.TextView
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.configuration.R import info.nightscout.configuration.R
@ -18,19 +30,23 @@ import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.ProfileSource import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.pump.Pump import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpSync import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.smoothing.Smoothing import info.nightscout.interfaces.smoothing.Smoothing
import info.nightscout.interfaces.source.BgSource import info.nightscout.interfaces.source.BgSource
import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppInitialized import info.nightscout.rx.events.EventAppInitialized
import info.nightscout.rx.events.EventConfigBuilderChange import info.nightscout.rx.events.EventConfigBuilderChange
import info.nightscout.rx.events.EventRebuildTabs import info.nightscout.rx.events.EventRebuildTabs
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.extensions.toVisibility
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import java.security.InvalidParameterException
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -43,7 +59,9 @@ class ConfigBuilderPlugin @Inject constructor(
private val rxBus: RxBus, private val rxBus: RxBus,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val uel: UserEntryLogger, private val uel: UserEntryLogger,
private val pumpSync: PumpSync private val pumpSync: PumpSync,
private val protectionCheck: ProtectionCheck,
private val uiInteraction: UiInteraction
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
@ -222,4 +240,115 @@ class ConfigBuilderPlugin @Inject constructor(
} }
} }
} }
override fun createViewsForPlugins(
@StringRes title: Int?,
@StringRes description: Int,
pluginType: PluginType,
plugins: List<PluginBase>,
pluginViewHolders: ArrayList<ConfigBuilder.PluginViewHolderInterface>,
fragment: Fragment?,
activity: FragmentActivity?,
parent: LinearLayout
) {
if (plugins.isEmpty()) return
val layoutInflater = fragment?.layoutInflater ?: activity?.layoutInflater ?: throw InvalidParameterException()
@Suppress("InflateParams")
val holder = layoutInflater.inflate(R.layout.configbuilder_single_category, null) as LinearLayout
(holder.findViewById<View>(R.id.category_title) as TextView).let {
if (title != null) it.text = rh.gs(title)
else it.visibility = View.GONE
}
(holder.findViewById<View>(R.id.category_description) as TextView).text = rh.gs(description)
val pluginContainer = holder.findViewById<LinearLayout>(R.id.category_plugins)
val appActivity = fragment?.activity ?: activity ?: throw InvalidParameterException()
for (plugin in plugins) {
val pluginViewHolder = PluginViewHolder(layoutInflater, appActivity, pluginType, plugin)
pluginContainer.addView(pluginViewHolder.baseView)
pluginViewHolders.add(pluginViewHolder)
}
parent.addView(holder)
}
inner class PluginViewHolder internal constructor(
layoutInflater: LayoutInflater,
private val activity: FragmentActivity,
private val pluginType: PluginType,
private val plugin: PluginBase
) : ConfigBuilder.PluginViewHolderInterface {
@Suppress("InflateParams")
val baseView: LinearLayout = layoutInflater.inflate(R.layout.configbuilder_single_plugin, null) as LinearLayout
private val enabledExclusive: RadioButton = baseView.findViewById(R.id.plugin_enabled_exclusive)
private val enabledInclusive: CheckBox = baseView.findViewById(R.id.plugin_enabled_inclusive)
private val pluginIcon: ImageView = baseView.findViewById(R.id.plugin_icon)
private val pluginIcon2: ImageView = baseView.findViewById(R.id.plugin_icon2)
private val pluginName: TextView = baseView.findViewById(R.id.plugin_name)
private val pluginDescription: TextView = baseView.findViewById(R.id.plugin_description)
private val pluginPreferences: ImageButton = baseView.findViewById(R.id.plugin_preferences)
private val pluginVisibility: CheckBox = baseView.findViewById(R.id.plugin_visibility)
init {
pluginVisibility.setOnClickListener {
plugin.setFragmentVisible(pluginType, pluginVisibility.isChecked)
storeSettings("CheckedCheckboxVisible")
rxBus.send(EventRebuildTabs())
logPluginStatus()
}
enabledExclusive.setOnClickListener {
switchAllowed(plugin, if (enabledExclusive.visibility == View.VISIBLE) enabledExclusive.isChecked else enabledInclusive.isChecked, activity, pluginType)
}
enabledInclusive.setOnClickListener {
switchAllowed(plugin, if (enabledExclusive.visibility == View.VISIBLE) enabledExclusive.isChecked else enabledInclusive.isChecked, activity, pluginType)
}
pluginPreferences.setOnClickListener {
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, {
val i = Intent(activity, uiInteraction.preferencesActivity)
i.putExtra("id", plugin.preferencesId)
activity.startActivity(i)
}, null)
}
update()
}
override fun update() {
enabledExclusive.visibility = areMultipleSelectionsAllowed(pluginType).not().toVisibility()
enabledInclusive.visibility = areMultipleSelectionsAllowed(pluginType).toVisibility()
enabledExclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isChecked = plugin.isEnabled(pluginType)
enabledInclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
enabledExclusive.isEnabled = !plugin.pluginDescription.alwaysEnabled
if (plugin.menuIcon != -1) {
pluginIcon.visibility = View.VISIBLE
pluginIcon.setImageDrawable(ContextCompat.getDrawable(activity, plugin.menuIcon))
if (plugin.menuIcon2 != -1) {
pluginIcon2.visibility = View.VISIBLE
pluginIcon2.setImageDrawable(ContextCompat.getDrawable(activity, plugin.menuIcon2))
} else {
pluginIcon2.visibility = View.GONE
}
} else {
pluginIcon.visibility = View.GONE
}
pluginName.text = plugin.name
if (plugin.description == null)
pluginDescription.visibility = View.GONE
else {
pluginDescription.visibility = View.VISIBLE
pluginDescription.text = plugin.description
}
pluginPreferences.visibility = if (plugin.preferencesId == -1 || !plugin.isEnabled(pluginType)) View.INVISIBLE else View.VISIBLE
pluginVisibility.visibility = plugin.hasFragment().toVisibility()
pluginVisibility.isEnabled = !(plugin.pluginDescription.neverVisible || plugin.pluginDescription.alwaysVisible) && plugin.isEnabled(pluginType)
pluginVisibility.isChecked = plugin.isFragmentVisible()
}
private fun areMultipleSelectionsAllowed(type: PluginType): Boolean {
return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP || type == PluginType.SYNC
}
}
} }

View file

@ -87,17 +87,14 @@ class SWDefinition @Inject constructor(
return this return this
} }
private val screenSetupWizard get() = SWScreen(injector, R.string.nav_setupwizard) private val screenSetupWizard
.add( get() = SWScreen(injector, R.string.nav_setupwizard)
SWInfoText(injector) .add(SWInfoText(injector).label(R.string.welcometosetupwizard))
.label(R.string.welcometosetupwizard)
) private val screenEula
private val screenEula get() = SWScreen(injector, R.string.end_user_license_agreement) get() = SWScreen(injector, R.string.end_user_license_agreement)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(R.string.end_user_license_agreement_text))
SWInfoText(injector)
.label(R.string.end_user_license_agreement_text)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(
SWButton(injector) SWButton(injector)
@ -143,10 +140,7 @@ class SWDefinition @Inject constructor(
private val screenPermissionWindow private val screenPermissionWindow
get() = SWScreen(injector, R.string.permission) get() = SWScreen(injector, R.string.permission)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(rh.gs(R.string.need_system_window_permission)))
SWInfoText(injector)
.label(rh.gs(R.string.need_system_window_permission))
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add(SWButton(injector) .add(SWButton(injector)
.text(R.string.askforpermission) .text(R.string.askforpermission)
@ -155,12 +149,10 @@ class SWDefinition @Inject constructor(
.visibility { !Settings.canDrawOverlays(activity) } .visibility { !Settings.canDrawOverlays(activity) }
.validator { Settings.canDrawOverlays(activity) } .validator { Settings.canDrawOverlays(activity) }
private val screenPermissionBattery get() = SWScreen(injector, R.string.permission) private val screenPermissionBattery
get() = SWScreen(injector, R.string.permission)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(rh.gs(R.string.need_whitelisting, rh.gs(config.appName))))
SWInfoText(injector)
.label(rh.gs(R.string.need_whitelisting, rh.gs(config.appName)))
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add(SWButton(injector) .add(SWButton(injector)
.text(R.string.askforpermission) .text(R.string.askforpermission)
@ -169,12 +161,10 @@ class SWDefinition @Inject constructor(
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) } .visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) }
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) } .validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) }
private val screenPermissionBt get() = SWScreen(injector, R.string.permission) private val screenPermissionBt
get() = SWScreen(injector, R.string.permission)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(rh.gs(R.string.need_location_permission)))
SWInfoText(injector)
.label(rh.gs(R.string.need_location_permission))
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add(SWButton(injector) .add(SWButton(injector)
.text(R.string.askforpermission) .text(R.string.askforpermission)
@ -183,12 +173,10 @@ class SWDefinition @Inject constructor(
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) } .visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) }
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) } .validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) }
private val screenPermissionStore get() = SWScreen(injector, R.string.permission) private val screenPermissionStore
get() = SWScreen(injector, R.string.permission)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(rh.gs(R.string.need_storage_permission)))
SWInfoText(injector)
.label(rh.gs(R.string.need_storage_permission))
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add(SWButton(injector) .add(SWButton(injector)
.text(R.string.askforpermission) .text(R.string.askforpermission)
@ -197,79 +185,46 @@ class SWDefinition @Inject constructor(
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) } .visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) } .validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
private val screenImport get() = SWScreen(injector, R.string.import_setting) private val screenImport
.add( get() = SWScreen(injector, R.string.import_setting)
SWInfoText(injector) .add(SWInfoText(injector).label(R.string.storedsettingsfound))
.label(R.string.storedsettingsfound)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add(SWButton(injector) .add(SWButton(injector).text(R.string.import_setting).action { importExportPrefs.importSharedPreferences(activity) })
.text(R.string.import_setting)
.action { importExportPrefs.importSharedPreferences(activity) })
.visibility { importExportPrefs.prefsFileExists() && !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) } .visibility { importExportPrefs.prefsFileExists() && !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
private val screenNsClient get() = SWScreen(injector, R.string.configbuilder_sync) private val screenNsClient
get() = SWScreen(injector, R.string.configbuilder_sync)
.skippable(true) .skippable(true)
.add( .add(SWPlugin(injector, this).option(PluginType.SYNC, R.string.configbuilder_sync_description))
SWPlugin(injector, this)
.option(PluginType.SYNC, R.string.configbuilder_sync_description)
.makeVisible(false)
.label(info.nightscout.core.ui.R.string.configbuilder_insulin)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(SWInfoText(injector).label(R.string.syncinfotext))
SWInfoText(injector)
.label(R.string.syncinfotext)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(SWEventListener(injector, EventSWSyncStatus::class.java).label(R.string.status).initialStatus(activePlugin.activeNsClient?.status ?: ""))
SWEventListener(injector, EventSWSyncStatus::class.java)
.label(R.string.status)
.initialStatus(activePlugin.activeNsClient?.status ?: "")
)
.validator { activePlugin.activeNsClient?.connected == true && activePlugin.activeNsClient?.hasWritePermission == true } .validator { activePlugin.activeNsClient?.connected == true && activePlugin.activeNsClient?.hasWritePermission == true }
private val screenPatientName get() = SWScreen(injector, R.string.patient_name) private val screenPatientName
get() = SWScreen(injector, R.string.patient_name)
.skippable(true) .skippable(true)
.add( .add(SWInfoText(injector).label(R.string.patient_name_summary))
SWInfoText(injector) .add(SWEditString(injector).validator(SWTextValidator(String::isNotEmpty)).preferenceId(info.nightscout.core.utils.R.string.key_patient_name))
.label(R.string.patient_name_summary)
)
.add(
SWEditString(injector)
.validator(SWTextValidator(String::isNotEmpty))
.preferenceId(info.nightscout.core.utils.R.string.key_patient_name)
)
private val privacy get() = SWScreen(injector, R.string.privacy_settings) private val privacy
get() = SWScreen(injector, R.string.privacy_settings)
.skippable(true) .skippable(true)
.add( .add(SWInfoText(injector).label(R.string.privacy_summary))
SWInfoText(injector) .add(SWPreference(injector, this).option(R.xml.pref_datachoices))
.label(R.string.privacy_summary)
)
.add(
SWPreference(injector, this)
.option(R.xml.pref_datachoices)
)
private val screenMasterPassword get() = SWScreen(injector, info.nightscout.core.ui.R.string.master_password) private val screenMasterPassword
get() = SWScreen(injector, info.nightscout.core.ui.R.string.master_password)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(info.nightscout.core.ui.R.string.master_password))
SWInfoText(injector) .add(SWEditEncryptedPassword(injector, cryptoUtil).preferenceId(info.nightscout.core.utils.R.string.key_master_password))
.label(info.nightscout.core.ui.R.string.master_password)
)
.add(
SWEditEncryptedPassword(injector, cryptoUtil)
.preferenceId(info.nightscout.core.utils.R.string.key_master_password)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(SWInfoText(injector).label(R.string.master_password_summary))
SWInfoText(injector)
.label(R.string.master_password_summary)
)
.validator { !cryptoUtil.checkPassword("", sp.getString(info.nightscout.core.utils.R.string.key_master_password, "")) } .validator { !cryptoUtil.checkPassword("", sp.getString(info.nightscout.core.utils.R.string.key_master_password, "")) }
private val screenAge get() = SWScreen(injector, info.nightscout.core.ui.R.string.patient_type) private val screenAge
get() = SWScreen(injector, info.nightscout.core.ui.R.string.patient_type)
.skippable(false) .skippable(false)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(
@ -300,28 +255,17 @@ class SWDefinition @Inject constructor(
&& sp.getInt(info.nightscout.core.utils.R.string.key_treatmentssafety_maxcarbs, 0) > 0 && sp.getInt(info.nightscout.core.utils.R.string.key_treatmentssafety_maxcarbs, 0) > 0
} }
private val screenInsulin get() = SWScreen(injector, info.nightscout.core.ui.R.string.configbuilder_insulin) private val screenInsulin
get() = SWScreen(injector, info.nightscout.core.ui.R.string.configbuilder_insulin)
.skippable(false) .skippable(false)
.add( .add(SWPlugin(injector, this).option(PluginType.INSULIN, R.string.configbuilder_insulin_description))
SWPlugin(injector, this)
.option(PluginType.INSULIN, R.string.configbuilder_insulin_description)
.makeVisible(false)
.label(info.nightscout.core.ui.R.string.configbuilder_insulin)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(SWInfoText(injector).label(R.string.diawarning))
SWInfoText(injector)
.label(R.string.diawarning)
)
private val screenBgSource private val screenBgSource
get() = SWScreen(injector, R.string.configbuilder_bgsource) get() = SWScreen(injector, R.string.configbuilder_bgsource)
.skippable(false) .skippable(false)
.add( .add(SWPlugin(injector, this).option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description))
SWPlugin(injector, this)
.option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description)
.label(R.string.configbuilder_bgsource)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
private val screenLocalProfile private val screenLocalProfile
@ -347,27 +291,19 @@ class SWDefinition @Inject constructor(
private val screenProfileSwitch private val screenProfileSwitch
get() = SWScreen(injector, info.nightscout.core.ui.R.string.careportal_profileswitch) get() = SWScreen(injector, info.nightscout.core.ui.R.string.careportal_profileswitch)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(info.nightscout.core.ui.R.string.profileswitch_ismissing))
SWInfoText(injector)
.label(info.nightscout.core.ui.R.string.profileswitch_ismissing)
)
.add(SWButton(injector) .add(SWButton(injector)
.text(R.string.doprofileswitch) .text(R.string.doprofileswitch)
.action { uiInteraction.runProfileSwitchDialog(activity.supportFragmentManager) }) .action { uiInteraction.runProfileSwitchDialog(activity.supportFragmentManager) })
.validator { profileFunction.getRequestedProfile() != null } .validator { profileFunction.getRequestedProfile() != null }
.visibility { profileFunction.getRequestedProfile() == null } .visibility { profileFunction.getRequestedProfile() == null }
private val screenPump get() = SWScreen(injector, R.string.configbuilder_pump) private val screenPump
get() = SWScreen(injector, R.string.configbuilder_pump)
.skippable(false) .skippable(false)
.add( .add(SWPlugin(injector, this).option(PluginType.PUMP, R.string.configbuilder_pump_description))
SWPlugin(injector, this)
.option(PluginType.PUMP, R.string.configbuilder_pump_description)
.label(R.string.configbuilder_pump)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add(SWInfoText(injector) .add(SWInfoText(injector).label(R.string.setupwizard_pump_pump_not_initialized).visibility { !isPumpInitialized() })
.label(R.string.setupwizard_pump_pump_not_initialized)
.visibility { !isPumpInitialized() })
.add( // Omnipod Eros only .add( // Omnipod Eros only
SWInfoText(injector) SWInfoText(injector)
.label(R.string.setupwizard_pump_waiting_for_riley_link_connection) .label(R.string.setupwizard_pump_waiting_for_riley_link_connection)
@ -402,26 +338,18 @@ class SWDefinition @Inject constructor(
|| activePump is OmnipodDash || activePump is OmnipodDash
} }
private val screenAps get() = SWScreen(injector, R.string.configbuilder_aps) private val screenAps
get() = SWScreen(injector, R.string.configbuilder_aps)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(R.string.setupwizard_aps_description))
SWInfoText(injector)
.label(R.string.setupwizard_aps_description)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(SWPlugin(injector, this).option(PluginType.APS, R.string.configbuilder_aps_description))
SWPlugin(injector, this)
.option(PluginType.APS, R.string.configbuilder_aps_description)
.label(R.string.configbuilder_aps)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(SWHtmlLink(injector).label("https://wiki.aaps.app"))
SWHtmlLink(injector)
.label("https://wiki.aaps.app")
)
.add(SWBreak(injector)) .add(SWBreak(injector))
private val screenApsMode get() = SWScreen(injector, R.string.apsmode_title) private val screenApsMode
get() = SWScreen(injector, R.string.apsmode_title)
.skippable(false) .skippable(false)
.add( .add(
SWRadioButton(injector) SWRadioButton(injector)
@ -431,12 +359,10 @@ class SWDefinition @Inject constructor(
) )
.validator { sp.contains(info.nightscout.core.utils.R.string.key_aps_mode) } .validator { sp.contains(info.nightscout.core.utils.R.string.key_aps_mode) }
private val screenLoop get() = SWScreen(injector, R.string.configbuilder_loop) private val screenLoop
get() = SWScreen(injector, R.string.configbuilder_loop)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(R.string.setupwizard_loop_description))
SWInfoText(injector)
.label(R.string.setupwizard_loop_description)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add(SWButton(injector) .add(SWButton(injector)
.text(info.nightscout.core.ui.R.string.enableloop) .text(info.nightscout.core.ui.R.string.enableloop)
@ -448,33 +374,27 @@ class SWDefinition @Inject constructor(
.validator { loop.isEnabled() } .validator { loop.isEnabled() }
.visibility { !loop.isEnabled() && config.APS } .visibility { !loop.isEnabled() && config.APS }
private val screenSensitivity get() = SWScreen(injector, R.string.configbuilder_sensitivity) private val screenSensitivity
get() = SWScreen(injector, R.string.configbuilder_sensitivity)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(R.string.setupwizard_sensitivity_description))
SWInfoText(injector) .add(SWHtmlLink(injector).label(R.string.setupwizard_sensitivity_url))
.label(R.string.setupwizard_sensitivity_description)
)
.add(
SWHtmlLink(injector)
.label(R.string.setupwizard_sensitivity_url)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(SWPlugin(injector, this).option(PluginType.SENSITIVITY, R.string.configbuilder_sensitivity_description))
SWPlugin(injector, this)
.option(PluginType.SENSITIVITY, R.string.configbuilder_sensitivity_description)
.label(R.string.configbuilder_sensitivity)
)
private val getScreenObjectives get() = SWScreen(injector, info.nightscout.core.ui.R.string.objectives) private val getScreenObjectives
get() = SWScreen(injector, info.nightscout.core.ui.R.string.objectives)
.skippable(false) .skippable(false)
.add( .add(SWInfoText(injector).label(R.string.startobjective))
SWInfoText(injector)
.label(R.string.startobjective)
)
.add(SWBreak(injector)) .add(SWBreak(injector))
.add( .add(
SWFragment(injector, this) SWFragment(injector, this)
.add(activity.supportFragmentManager.fragmentFactory.instantiate(ClassLoader.getSystemClassLoader(), (activePlugin.activeObjectives as PluginBase).pluginDescription.fragmentClass!!)) .add(
activity.supportFragmentManager.fragmentFactory.instantiate(
ClassLoader.getSystemClassLoader(),
(activePlugin.activeObjectives as PluginBase).pluginDescription.fragmentClass!!
)
)
//.add(ObjectivesFragment()) //.add(ObjectivesFragment())
) )
.validator { activePlugin.activeObjectives?.isStarted(Objectives.FIRST_OBJECTIVE) ?: false } .validator { activePlugin.activeObjectives?.isStarted(Objectives.FIRST_OBJECTIVE) ?: false }

View file

@ -1,22 +1,19 @@
package info.nightscout.configuration.setupwizard.elements package info.nightscout.configuration.setupwizard.elements
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.RadioButton import androidx.annotation.StringRes
import android.widget.RadioGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.configuration.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.configuration.setupwizard.SWDefinition import info.nightscout.configuration.setupwizard.SWDefinition
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.ConfigBuilder import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.events.EventConfigBuilderChange import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.events.EventSWUpdate import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.security.InvalidParameterException
import javax.inject.Inject import javax.inject.Inject
class SWPlugin(injector: HasAndroidInjector, private val definition: SWDefinition) : SWItem(injector, Type.PLUGIN) { class SWPlugin(injector: HasAndroidInjector, private val definition: SWDefinition) : SWItem(injector, Type.PLUGIN) {
@ -24,89 +21,39 @@ class SWPlugin(injector: HasAndroidInjector, private val definition: SWDefinitio
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var configBuilder: ConfigBuilder @Inject lateinit var configBuilder: ConfigBuilder
@Inject lateinit var uiInteraction: UiInteraction @Inject lateinit var uiInteraction: UiInteraction
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var fabricPrivacy: FabricPrivacy
private val disposable = CompositeDisposable()
private val pluginViewHolders = ArrayList<ConfigBuilder.PluginViewHolderInterface>()
private var pType: PluginType? = null private var pType: PluginType? = null
private var radioGroup: RadioGroup? = null @StringRes private var pluginDescription = 0
private var pluginDescription = 0
private var makeVisible = true
private var fragment: Fragment? = null // TODO: Adrian how to clear disposable in this case?
init {
disposable += rxBus
.toObservable(EventConfigBuilderUpdateGui::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ for (pluginViewHolder in pluginViewHolders) pluginViewHolder.update() }, fabricPrivacy::logException)
}
fun option(pType: PluginType, pluginDescription: Int): SWPlugin { fun option(pType: PluginType, @StringRes pluginDescription: Int): SWPlugin {
this.pType = pType this.pType = pType
this.pluginDescription = pluginDescription this.pluginDescription = pluginDescription
return this return this
} }
fun makeVisible(makeVisible: Boolean): SWPlugin {
this.makeVisible = makeVisible
return this
}
override fun generateDialog(layout: LinearLayout) { override fun generateDialog(layout: LinearLayout) {
var selectedPlugin: PluginBase? = null val pType = this.pType ?: throw InvalidParameterException()
val context = layout.context configBuilder.createViewsForPlugins(
radioGroup = RadioGroup(context) title = null,
radioGroup?.clearCheck() description = pluginDescription,
val pluginsInCategory = activePlugin.getSpecificPluginsList(pType!!) pluginType = pType,
radioGroup?.orientation = LinearLayout.VERTICAL plugins = activePlugin.getSpecificPluginsVisibleInList(pType),
radioGroup?.visibility = View.VISIBLE pluginViewHolders = pluginViewHolders,
val pDesc = TextView(context) activity = definition.activity,
pDesc.setText(pluginDescription) parent = layout
var params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) )
params.setMargins(0, 0, 0, 40)
pDesc.layoutParams = params
layout.addView(pDesc)
for (i in pluginsInCategory.indices) {
val rdBtn = RadioButton(context)
val p = pluginsInCategory[i]
rdBtn.id = View.generateViewId()
rdBtn.text = p.name
if (p.isEnabled()) {
rdBtn.isChecked = true
selectedPlugin = p
}
rdBtn.tag = p
radioGroup?.addView(rdBtn)
params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
params.setMargins(80, 0, 0, 0)
val desc = TextView(context)
desc.text = p.description
desc.layoutParams = params
radioGroup?.addView(desc)
}
radioGroup?.setOnCheckedChangeListener { group: RadioGroup, checkedId: Int ->
val rb = group.findViewById<RadioButton>(checkedId)
val plugin = rb.tag as PluginBase
plugin.setPluginEnabled(pType!!, rb.isChecked)
plugin.setFragmentVisible(pType!!, rb.isChecked && makeVisible)
configBuilder.processOnEnabledCategoryChanged(plugin, pType!!)
configBuilder.storeSettings("SetupWizard")
rxBus.send(EventConfigBuilderChange())
rxBus.send(EventSWUpdate(false))
addConfiguration(layout, plugin)
}
layout.addView(radioGroup)
selectedPlugin?.let { addConfiguration(layout, it) }
super.generateDialog(layout) super.generateDialog(layout)
} }
private fun addConfiguration(layout: LinearLayout, plugin: PluginBase) {
if (plugin.preferencesId != -1) {
fragment = Class.forName(uiInteraction.myPreferenceFragment.name).newInstance() as Fragment //MyPreferenceFragment()
fragment?.let {
it.arguments = Bundle().also { it.putInt("id", plugin.preferencesId) }
definition.activity.supportFragmentManager.beginTransaction().run {
replace(layout.id, it)
commit()
}
}
} else {
definition.activity.supportFragmentManager.beginTransaction().run {
fragment?.let { remove(it) }
fragment = null
commit()
}
}
}
} }

View file

@ -28,7 +28,7 @@
<string name="master_password_summary">Master password is used for backup encryption and to override security in application. Remember it or store on a safe place.</string> <string name="master_password_summary">Master password is used for backup encryption and to override security in application. Remember it or store on a safe place.</string>
<string name="current_master_password">Current master password</string> <string name="current_master_password">Current master password</string>
<string name="common_values">Use values of your largest food you usually eat\n</string> <string name="common_values">Use values of your largest food you usually eat\n</string>
<string name="syncinfotext">Synchronize data to the cloud. You can skip this part now but you will not be able to pass objectives until you set it up.</string> <string name="syncinfotext">Synchronize data to the cloud. You can skip this part now but you will not be able to pass objectives until you set up Nightscout or Tidepool client.</string>
<string name="status">Status:</string> <string name="status">Status:</string>
<string name="patient_name">Patient name</string> <string name="patient_name">Patient name</string>
<string name="patient_name_summary">Please provide patient name or nickname to differentiate among multiple setups</string> <string name="patient_name_summary">Please provide patient name or nickname to differentiate among multiple setups</string>

View file

@ -8,6 +8,7 @@ import info.nightscout.interfaces.iob.IobCobCalculator
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.pump.VirtualPump import info.nightscout.interfaces.pump.VirtualPump
import info.nightscout.interfaces.sync.Tidepool
import info.nightscout.plugins.constraints.R import info.nightscout.plugins.constraints.R
import javax.inject.Inject import javax.inject.Inject
@ -18,21 +19,22 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
@Inject lateinit var persistenceLayer: PersistenceLayer @Inject lateinit var persistenceLayer: PersistenceLayer
@Inject lateinit var loop: Loop @Inject lateinit var loop: Loop
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
val tidepoolPlugin get() = activePlugin.getSpecificPluginsListByInterface(Tidepool::class.java).firstOrNull() as Tidepool?
init { init {
tasks.add(object : Task(this, R.string.objectives_bgavailableinns) { tasks.add(object : Task(this, R.string.objectives_bgavailableinns) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return sp.getBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, false) return sp.getBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, false) || tidepoolPlugin?.hasWritePermission == true
} }
}) })
tasks.add(object : Task(this, R.string.synchaswritepermission) { tasks.add(object : Task(this, R.string.synchaswritepermission) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return activePlugin.firstActiveSync?.hasWritePermission == true return activePlugin.firstActiveSync?.hasWritePermission == true || tidepoolPlugin?.hasWritePermission == true
} }
}) })
tasks.add(object : Task(this, info.nightscout.core.ui.R.string.virtualpump_uploadstatus_title) { tasks.add(object : Task(this, info.nightscout.core.ui.R.string.virtualpump_uploadstatus_title) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return sp.getBoolean(info.nightscout.core.utils.R.string.key_virtual_pump_upload_status, false) return sp.getBoolean(info.nightscout.core.utils.R.string.key_virtual_pump_upload_status, false) || tidepoolPlugin?.hasWritePermission == true
} }
override fun shouldBeIgnored(): Boolean { override fun shouldBeIgnored(): Boolean {
@ -42,7 +44,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
tasks.add( tasks.add(
object : Task(this, R.string.objectives_pumpstatusavailableinns) { object : Task(this, R.string.objectives_pumpstatusavailableinns) {
override fun isCompleted(): Boolean { override fun isCompleted(): Boolean {
return sp.getBoolean(info.nightscout.core.utils.R.string.key_objectives_pump_status_is_available_in_ns, false) return sp.getBoolean(info.nightscout.core.utils.R.string.key_objectives_pump_status_is_available_in_ns, false) || tidepoolPlugin?.hasWritePermission == true
} }
}.learned(Learned(R.string.objectives_0_learned)) }.learned(Learned(R.string.objectives_0_learned))
) )

View file

@ -31,8 +31,8 @@
<string name="objectives_auto_objective">Enabling automation</string> <string name="objectives_auto_objective">Enabling automation</string>
<string name="objectives_auto_gate">Read the docs on how automation works. Set up your first simple rules. Instead of action let AAPS display only notification. When you are sure automation is triggered at the right time replace notification by real action. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string> <string name="objectives_auto_gate">Read the docs on how automation works. Set up your first simple rules. Instead of action let AAPS display only notification. When you are sure automation is triggered at the right time replace notification by real action. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string>
<string name="objectives_auto_learned">Automation can be a good servant but a bad master. Don\'t overuse it. Do not try to replace underlying algorithm. Test the rule with message only before use. It depends on order.</string> <string name="objectives_auto_learned">Automation can be a good servant but a bad master. Don\'t overuse it. Do not try to replace underlying algorithm. Test the rule with message only before use. It depends on order.</string>
<string name="objectives_bgavailableinns">BG available in NS</string> <string name="objectives_bgavailableinns">BG available in NS or Tidepool</string>
<string name="objectives_pumpstatusavailableinns">Pump status available in NS</string> <string name="objectives_pumpstatusavailableinns">Pump status available in NS or Tidepool</string>
<string name="objectives_manualenacts">Manual enacts</string> <string name="objectives_manualenacts">Manual enacts</string>
<string name="accomplished">Accomplished: %1$s</string> <string name="accomplished">Accomplished: %1$s</string>
<string name="objectives_usage_objective">Learn how to control AAPS</string> <string name="objectives_usage_objective">Learn how to control AAPS</string>

View file

@ -92,7 +92,7 @@ class RandomBgPlugin @Inject constructor(
} }
override fun specialEnableCondition(): Boolean { override fun specialEnableCondition(): Boolean {
return isRunningTest() || config.isUnfinishedMode() || virtualPump.isEnabled() && config.isEngineeringMode() return isRunningTest() || virtualPump.isEnabled() && config.isEngineeringMode()
} }
private fun handleNewData() { private fun handleNewData() {

View file

@ -62,9 +62,7 @@ class DataBroadcastPlugin @Inject constructor(
PluginDescription() PluginDescription()
.mainType(PluginType.SYNC) .mainType(PluginType.SYNC)
.pluginName(R.string.data_broadcaster) .pluginName(R.string.data_broadcaster)
.alwaysEnabled(true) .description(R.string.data_broadcaster_description),
.neverVisible(true)
.showInList(false),
aapsLogger, rh, injector aapsLogger, rh, injector
) { ) {

View file

@ -11,6 +11,7 @@ import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.sync.Sync import info.nightscout.interfaces.sync.Sync
import info.nightscout.interfaces.sync.Tidepool
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HtmlHelper import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
@ -28,6 +29,7 @@ import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.events.EventNewBG import info.nightscout.rx.events.EventNewBG
import info.nightscout.rx.events.EventPreferenceChange import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.events.EventSWSyncStatus
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
@ -53,7 +55,7 @@ class TidepoolPlugin @Inject constructor(
private val rateLimit: RateLimit, private val rateLimit: RateLimit,
private val receiverDelegate: ReceiverDelegate, private val receiverDelegate: ReceiverDelegate,
private val uiInteraction: UiInteraction private val uiInteraction: UiInteraction
) : Sync, PluginBase( ) : Sync, Tidepool, PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.SYNC) .mainType(PluginType.SYNC)
.pluginName(R.string.tidepool) .pluginName(R.string.tidepool)
@ -99,7 +101,11 @@ class TidepoolPlugin @Inject constructor(
disposable += rxBus disposable += rxBus
.toObservable(EventTidepoolStatus::class.java) .toObservable(EventTidepoolStatus::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> addToLog(event) }, fabricPrivacy::logException) .subscribe({ event ->
addToLog(event)
// Pass to setup wizard
rxBus.send(EventSWSyncStatus(event.status))
}, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventNewBG::class.java) .toObservable(EventNewBG::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)

View file

@ -105,6 +105,8 @@
<string name="ns_alarm_urgent_stale_data_value_label">Urgent stale data threshold [min]</string> <string name="ns_alarm_urgent_stale_data_value_label">Urgent stale data threshold [min]</string>
<string name="ns_log_app_started_event">Log app start to NS</string> <string name="ns_log_app_started_event">Log app start to NS</string>
<string name="copy_existing_values">Copy NS settings (if exists)?</string> <string name="copy_existing_values">Copy NS settings (if exists)?</string>
<string name="ns_use_ws_title">Connect to websockets</string>
<string name="ns_use_ws_summary">Enabling means: faster updates, receiving alarms and announcements and higher battery consumption similar to v1. All other uploaders to NS must use v3 protocol.</string>
<!-- Tidepool --> <!-- Tidepool -->
<string name="key_tidepool_username" translatable="false">tidepool_username</string> <string name="key_tidepool_username" translatable="false">tidepool_username</string>
@ -177,8 +179,7 @@
<!-- DataBroadcast--> <!-- DataBroadcast-->
<string name="data_broadcaster" translatable="false">Data Broadcaster</string> <string name="data_broadcaster">Data Broadcaster</string>
<string name="ns_use_ws_title">Connect to websockets</string> <string name="data_broadcaster_description" translatable="false">Broadcast data to other apps like Garmin watch</string>
<string name="ns_use_ws_summary">Enabling means: faster updates, receiving alarms and announcements and higher battery consumption similar to v1. All other uploaderds to NS must use v3 protocol.</string>
</resources> </resources>