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
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.PluginType
interface ConfigBuilder {
/**
* Called during start of app to load configuration and start enabled plugins
*/
fun initialize()
/**
* Store current configuration to SharedPreferences
*/
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)
/**
* Make sure plugins configuration is valid after enabling/disabling plugin
*/
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="canceling_tbr_failed">Canceling of temporary basal 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="iob_label">Insulin on Board (IOB)</string>

View file

@ -1,36 +1,24 @@
package info.nightscout.configuration.configBuilder
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
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 info.nightscout.configuration.R
import info.nightscout.configuration.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.configuration.databinding.ConfigbuilderFragmentBinding
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.protection.ProtectionCheck.Protection.PREFERENCES
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventRebuildTabs
import info.nightscout.shared.extensions.toVisibility
import info.nightscout.shared.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
@ -39,17 +27,15 @@ class ConfigBuilderFragment : DaggerFragment() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBus
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@Inject lateinit var configBuilder: ConfigBuilder
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var config: Config
@Inject lateinit var ctx: Context
@Inject lateinit var uiInteraction: UiInteraction
private var disposable: CompositeDisposable = CompositeDisposable()
private val pluginViewHolders = ArrayList<PluginViewHolder>()
private val pluginViewHolders = ArrayList<ConfigBuilder.PluginViewHolderInterface>()
private var inMenu = false
private var queryingProtection = false
private var _binding: ConfigbuilderFragmentBinding? = null
@ -98,119 +84,111 @@ class ConfigBuilderFragment : DaggerFragment() {
@Synchronized
private fun updateGUI() {
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())
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) {
createViewsForPlugins(R.string.configbuilder_bgsource, R.string.configbuilder_bgsource_description, PluginType.BGSOURCE, activePlugin.getSpecificPluginsVisibleInList(PluginType.BGSOURCE))
createViewsForPlugins(R.string.configbuilder_smoothing, R.string.configbuilder_smoothing_description, PluginType.SMOOTHING, activePlugin.getSpecificPluginsVisibleInList(PluginType.SMOOTHING))
createViewsForPlugins(R.string.configbuilder_pump, R.string.configbuilder_pump_description, PluginType.PUMP, activePlugin.getSpecificPluginsVisibleInList(PluginType.PUMP))
configBuilder.createViewsForPlugins(
title = R.string.configbuilder_bgsource,
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())
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) {
createViewsForPlugins(R.string.configbuilder_aps, R.string.configbuilder_aps_description, PluginType.APS, activePlugin.getSpecificPluginsVisibleInList(PluginType.APS))
createViewsForPlugins(R.string.configbuilder_loop, R.string.configbuilder_loop_description, PluginType.LOOP, activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP))
createViewsForPlugins(info.nightscout.core.ui.R.string.constraints, R.string.configbuilder_constraints_description, PluginType.CONSTRAINTS, activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS))
}
createViewsForPlugins(R.string.configbuilder_sync, R.string.configbuilder_sync_description, PluginType.SYNC, activePlugin.getSpecificPluginsVisibleInList(PluginType.SYNC))
createViewsForPlugins(R.string.configbuilder_general, R.string.configbuilder_general_description, PluginType.GENERAL, activePlugin.getSpecificPluginsVisibleInList(PluginType.GENERAL))
}
private fun createViewsForPlugins(@StringRes title: Int, @StringRes description: Int, pluginType: PluginType, plugins: List<PluginBase>) {
if (plugins.isEmpty()) return
@Suppress("InflateParams")
val parent = layoutInflater.inflate(R.layout.configbuilder_single_category, null) as LinearLayout
(parent.findViewById<View>(R.id.category_title) as TextView).text = rh.gs(title)
(parent.findViewById<View>(R.id.category_description) as TextView).text = rh.gs(description)
val pluginContainer = parent.findViewById<LinearLayout>(R.id.category_plugins)
for (plugin in plugins) {
val pluginViewHolder = PluginViewHolder(this, pluginType, plugin)
pluginContainer.addView(pluginViewHolder.baseView)
pluginViewHolders.add(pluginViewHolder)
}
binding.categories.addView(parent)
}
inner class PluginViewHolder internal constructor(private val fragment: ConfigBuilderFragment,
private val pluginType: PluginType,
private val plugin: PluginBase
) {
@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_aps,
description = R.string.configbuilder_aps_description,
pluginType = PluginType.APS,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.APS),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
configBuilder.createViewsForPlugins(
title = R.string.configbuilder_loop,
description = R.string.configbuilder_loop_description,
pluginType = PluginType.LOOP,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.LOOP),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
configBuilder.createViewsForPlugins(
title = info.nightscout.core.ui.R.string.constraints,
description = R.string.configbuilder_constraints_description,
pluginType = PluginType.CONSTRAINTS,
plugins = activePlugin.getSpecificPluginsVisibleInList(PluginType.CONSTRAINTS),
pluginViewHolders = pluginViewHolders,
fragment = this,
parent = binding.categories
)
}
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() {

View file

@ -1,5 +1,17 @@
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 dagger.android.HasAndroidInjector
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.PluginType
import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.smoothing.Smoothing
import info.nightscout.interfaces.source.BgSource
import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppInitialized
import info.nightscout.rx.events.EventConfigBuilderChange
import info.nightscout.rx.events.EventRebuildTabs
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.extensions.toVisibility
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.security.InvalidParameterException
import javax.inject.Inject
import javax.inject.Singleton
@ -43,7 +59,9 @@ class ConfigBuilderPlugin @Inject constructor(
private val rxBus: RxBus,
private val activePlugin: ActivePlugin,
private val uel: UserEntryLogger,
private val pumpSync: PumpSync
private val pumpSync: PumpSync,
private val protectionCheck: ProtectionCheck,
private val uiInteraction: UiInteraction
) : PluginBase(
PluginDescription()
.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
}
private val screenSetupWizard get() = SWScreen(injector, R.string.nav_setupwizard)
.add(
SWInfoText(injector)
.label(R.string.welcometosetupwizard)
)
private val screenEula get() = SWScreen(injector, R.string.end_user_license_agreement)
private val screenSetupWizard
get() = SWScreen(injector, R.string.nav_setupwizard)
.add(SWInfoText(injector).label(R.string.welcometosetupwizard))
private val screenEula
get() = SWScreen(injector, R.string.end_user_license_agreement)
.skippable(false)
.add(
SWInfoText(injector)
.label(R.string.end_user_license_agreement_text)
)
.add(SWInfoText(injector).label(R.string.end_user_license_agreement_text))
.add(SWBreak(injector))
.add(
SWButton(injector)
@ -143,10 +140,7 @@ class SWDefinition @Inject constructor(
private val screenPermissionWindow
get() = SWScreen(injector, R.string.permission)
.skippable(false)
.add(
SWInfoText(injector)
.label(rh.gs(R.string.need_system_window_permission))
)
.add(SWInfoText(injector).label(rh.gs(R.string.need_system_window_permission)))
.add(SWBreak(injector))
.add(SWButton(injector)
.text(R.string.askforpermission)
@ -155,12 +149,10 @@ class SWDefinition @Inject constructor(
.visibility { !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)
.add(
SWInfoText(injector)
.label(rh.gs(R.string.need_whitelisting, rh.gs(config.appName)))
)
.add(SWInfoText(injector).label(rh.gs(R.string.need_whitelisting, rh.gs(config.appName))))
.add(SWBreak(injector))
.add(SWButton(injector)
.text(R.string.askforpermission)
@ -169,12 +161,10 @@ class SWDefinition @Inject constructor(
.visibility { 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)
.add(
SWInfoText(injector)
.label(rh.gs(R.string.need_location_permission))
)
.add(SWInfoText(injector).label(rh.gs(R.string.need_location_permission)))
.add(SWBreak(injector))
.add(SWButton(injector)
.text(R.string.askforpermission)
@ -183,12 +173,10 @@ class SWDefinition @Inject constructor(
.visibility { 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)
.add(
SWInfoText(injector)
.label(rh.gs(R.string.need_storage_permission))
)
.add(SWInfoText(injector).label(rh.gs(R.string.need_storage_permission)))
.add(SWBreak(injector))
.add(SWButton(injector)
.text(R.string.askforpermission)
@ -197,79 +185,46 @@ class SWDefinition @Inject constructor(
.visibility { 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)
.add(
SWInfoText(injector)
.label(R.string.storedsettingsfound)
)
private val screenImport
get() = SWScreen(injector, R.string.import_setting)
.add(SWInfoText(injector).label(R.string.storedsettingsfound))
.add(SWBreak(injector))
.add(SWButton(injector)
.text(R.string.import_setting)
.action { importExportPrefs.importSharedPreferences(activity) })
.add(SWButton(injector).text(R.string.import_setting).action { importExportPrefs.importSharedPreferences(activity) })
.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)
.add(
SWPlugin(injector, this)
.option(PluginType.SYNC, R.string.configbuilder_sync_description)
.makeVisible(false)
.label(info.nightscout.core.ui.R.string.configbuilder_insulin)
)
.add(SWPlugin(injector, this).option(PluginType.SYNC, R.string.configbuilder_sync_description))
.add(SWBreak(injector))
.add(
SWInfoText(injector)
.label(R.string.syncinfotext)
)
.add(SWInfoText(injector).label(R.string.syncinfotext))
.add(SWBreak(injector))
.add(
SWEventListener(injector, EventSWSyncStatus::class.java)
.label(R.string.status)
.initialStatus(activePlugin.activeNsClient?.status ?: "")
)
.add(SWEventListener(injector, EventSWSyncStatus::class.java).label(R.string.status).initialStatus(activePlugin.activeNsClient?.status ?: ""))
.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)
.add(
SWInfoText(injector)
.label(R.string.patient_name_summary)
)
.add(
SWEditString(injector)
.validator(SWTextValidator(String::isNotEmpty))
.preferenceId(info.nightscout.core.utils.R.string.key_patient_name)
)
.add(SWInfoText(injector).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)
.add(
SWInfoText(injector)
.label(R.string.privacy_summary)
)
.add(
SWPreference(injector, this)
.option(R.xml.pref_datachoices)
)
.add(SWInfoText(injector).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)
.add(
SWInfoText(injector)
.label(info.nightscout.core.ui.R.string.master_password)
)
.add(
SWEditEncryptedPassword(injector, cryptoUtil)
.preferenceId(info.nightscout.core.utils.R.string.key_master_password)
)
.add(SWInfoText(injector).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(
SWInfoText(injector)
.label(R.string.master_password_summary)
)
.add(SWInfoText(injector).label(R.string.master_password_summary))
.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)
.add(SWBreak(injector))
.add(
@ -300,28 +255,17 @@ class SWDefinition @Inject constructor(
&& 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)
.add(
SWPlugin(injector, this)
.option(PluginType.INSULIN, R.string.configbuilder_insulin_description)
.makeVisible(false)
.label(info.nightscout.core.ui.R.string.configbuilder_insulin)
)
.add(SWPlugin(injector, this).option(PluginType.INSULIN, R.string.configbuilder_insulin_description))
.add(SWBreak(injector))
.add(
SWInfoText(injector)
.label(R.string.diawarning)
)
.add(SWInfoText(injector).label(R.string.diawarning))
private val screenBgSource
get() = SWScreen(injector, R.string.configbuilder_bgsource)
.skippable(false)
.add(
SWPlugin(injector, this)
.option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description)
.label(R.string.configbuilder_bgsource)
)
.add(SWPlugin(injector, this).option(PluginType.BGSOURCE, R.string.configbuilder_bgsource_description))
.add(SWBreak(injector))
private val screenLocalProfile
@ -347,27 +291,19 @@ class SWDefinition @Inject constructor(
private val screenProfileSwitch
get() = SWScreen(injector, info.nightscout.core.ui.R.string.careportal_profileswitch)
.skippable(false)
.add(
SWInfoText(injector)
.label(info.nightscout.core.ui.R.string.profileswitch_ismissing)
)
.add(SWInfoText(injector).label(info.nightscout.core.ui.R.string.profileswitch_ismissing))
.add(SWButton(injector)
.text(R.string.doprofileswitch)
.action { uiInteraction.runProfileSwitchDialog(activity.supportFragmentManager) })
.validator { 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)
.add(
SWPlugin(injector, this)
.option(PluginType.PUMP, R.string.configbuilder_pump_description)
.label(R.string.configbuilder_pump)
)
.add(SWPlugin(injector, this).option(PluginType.PUMP, R.string.configbuilder_pump_description))
.add(SWBreak(injector))
.add(SWInfoText(injector)
.label(R.string.setupwizard_pump_pump_not_initialized)
.visibility { !isPumpInitialized() })
.add(SWInfoText(injector).label(R.string.setupwizard_pump_pump_not_initialized).visibility { !isPumpInitialized() })
.add( // Omnipod Eros only
SWInfoText(injector)
.label(R.string.setupwizard_pump_waiting_for_riley_link_connection)
@ -402,26 +338,18 @@ class SWDefinition @Inject constructor(
|| 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)
.add(
SWInfoText(injector)
.label(R.string.setupwizard_aps_description)
)
.add(SWInfoText(injector).label(R.string.setupwizard_aps_description))
.add(SWBreak(injector))
.add(
SWPlugin(injector, this)
.option(PluginType.APS, R.string.configbuilder_aps_description)
.label(R.string.configbuilder_aps)
)
.add(SWPlugin(injector, this).option(PluginType.APS, R.string.configbuilder_aps_description))
.add(SWBreak(injector))
.add(
SWHtmlLink(injector)
.label("https://wiki.aaps.app")
)
.add(SWHtmlLink(injector).label("https://wiki.aaps.app"))
.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)
.add(
SWRadioButton(injector)
@ -431,12 +359,10 @@ class SWDefinition @Inject constructor(
)
.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)
.add(
SWInfoText(injector)
.label(R.string.setupwizard_loop_description)
)
.add(SWInfoText(injector).label(R.string.setupwizard_loop_description))
.add(SWBreak(injector))
.add(SWButton(injector)
.text(info.nightscout.core.ui.R.string.enableloop)
@ -448,36 +374,30 @@ class SWDefinition @Inject constructor(
.validator { loop.isEnabled() }
.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)
.add(
SWInfoText(injector)
.label(R.string.setupwizard_sensitivity_description)
)
.add(
SWHtmlLink(injector)
.label(R.string.setupwizard_sensitivity_url)
)
.add(SWInfoText(injector).label(R.string.setupwizard_sensitivity_description))
.add(SWHtmlLink(injector).label(R.string.setupwizard_sensitivity_url))
.add(SWBreak(injector))
.add(
SWPlugin(injector, this)
.option(PluginType.SENSITIVITY, R.string.configbuilder_sensitivity_description)
.label(R.string.configbuilder_sensitivity)
)
.add(SWPlugin(injector, this).option(PluginType.SENSITIVITY, R.string.configbuilder_sensitivity_description))
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)
.add(
SWInfoText(injector)
.label(R.string.startobjective)
)
.add(SWInfoText(injector).label(R.string.startobjective))
.add(SWBreak(injector))
.add(
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())
)
.validator { activePlugin.activeObjectives?.isStarted(Objectives.FIRST_OBJECTIVE) ?: false}
.validator { activePlugin.activeObjectives?.isStarted(Objectives.FIRST_OBJECTIVE) ?: false }
.visibility { config.APS && !(activePlugin.activeObjectives?.isStarted(Objectives.FIRST_OBJECTIVE) ?: false) }
private fun swDefinitionFull() = // List all the screens here

View file

@ -1,22 +1,19 @@
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.RadioButton
import android.widget.RadioGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.annotation.StringRes
import dagger.android.HasAndroidInjector
import info.nightscout.configuration.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.configuration.setupwizard.SWDefinition
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.rx.events.EventConfigBuilderChange
import info.nightscout.rx.events.EventSWUpdate
import info.nightscout.rx.AapsSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.security.InvalidParameterException
import javax.inject.Inject
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 configBuilder: ConfigBuilder
@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 radioGroup: RadioGroup? = null
private var pluginDescription = 0
private var makeVisible = true
@StringRes private var pluginDescription = 0
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.pluginDescription = pluginDescription
return this
}
fun makeVisible(makeVisible: Boolean): SWPlugin {
this.makeVisible = makeVisible
return this
}
override fun generateDialog(layout: LinearLayout) {
var selectedPlugin: PluginBase? = null
val context = layout.context
radioGroup = RadioGroup(context)
radioGroup?.clearCheck()
val pluginsInCategory = activePlugin.getSpecificPluginsList(pType!!)
radioGroup?.orientation = LinearLayout.VERTICAL
radioGroup?.visibility = View.VISIBLE
val pDesc = TextView(context)
pDesc.setText(pluginDescription)
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) }
val pType = this.pType ?: throw InvalidParameterException()
configBuilder.createViewsForPlugins(
title = null,
description = pluginDescription,
pluginType = pType,
plugins = activePlugin.getSpecificPluginsVisibleInList(pType),
pluginViewHolders = pluginViewHolders,
activity = definition.activity,
parent = 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="current_master_password">Current master password</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="patient_name">Patient name</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.PluginBase
import info.nightscout.interfaces.pump.VirtualPump
import info.nightscout.interfaces.sync.Tidepool
import info.nightscout.plugins.constraints.R
import javax.inject.Inject
@ -18,21 +19,22 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
@Inject lateinit var persistenceLayer: PersistenceLayer
@Inject lateinit var loop: Loop
@Inject lateinit var iobCobCalculator: IobCobCalculator
val tidepoolPlugin get() = activePlugin.getSpecificPluginsListByInterface(Tidepool::class.java).firstOrNull() as Tidepool?
init {
tasks.add(object : Task(this, R.string.objectives_bgavailableinns) {
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) {
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) {
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 {
@ -42,7 +44,7 @@ class Objective0(injector: HasAndroidInjector) : Objective(injector, "config", R
tasks.add(
object : Task(this, R.string.objectives_pumpstatusavailableinns) {
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))
)

View file

@ -31,8 +31,8 @@
<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_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_pumpstatusavailableinns">Pump status available in NS</string>
<string name="objectives_bgavailableinns">BG available in NS or Tidepool</string>
<string name="objectives_pumpstatusavailableinns">Pump status available in NS or Tidepool</string>
<string name="objectives_manualenacts">Manual enacts</string>
<string name="accomplished">Accomplished: %1$s</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 {
return isRunningTest() || config.isUnfinishedMode() || virtualPump.isEnabled() && config.isEngineeringMode()
return isRunningTest() || virtualPump.isEnabled() && config.isEngineeringMode()
}
private fun handleNewData() {

View file

@ -62,9 +62,7 @@ class DataBroadcastPlugin @Inject constructor(
PluginDescription()
.mainType(PluginType.SYNC)
.pluginName(R.string.data_broadcaster)
.alwaysEnabled(true)
.neverVisible(true)
.showInList(false),
.description(R.string.data_broadcaster_description),
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.PluginType
import info.nightscout.interfaces.sync.Sync
import info.nightscout.interfaces.sync.Tidepool
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HtmlHelper
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.EventNewBG
import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.events.EventSWSyncStatus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper
@ -53,7 +55,7 @@ class TidepoolPlugin @Inject constructor(
private val rateLimit: RateLimit,
private val receiverDelegate: ReceiverDelegate,
private val uiInteraction: UiInteraction
) : Sync, PluginBase(
) : Sync, Tidepool, PluginBase(
PluginDescription()
.mainType(PluginType.SYNC)
.pluginName(R.string.tidepool)
@ -99,7 +101,11 @@ class TidepoolPlugin @Inject constructor(
disposable += rxBus
.toObservable(EventTidepoolStatus::class.java)
.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
.toObservable(EventNewBG::class.java)
.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_log_app_started_event">Log app start to NS</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 -->
<string name="key_tidepool_username" translatable="false">tidepool_username</string>
@ -177,8 +179,7 @@
<!-- DataBroadcast-->
<string name="data_broadcaster" translatable="false">Data Broadcaster</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 uploaderds to NS must use v3 protocol.</string>
<string name="data_broadcaster">Data Broadcaster</string>
<string name="data_broadcaster_description" translatable="false">Broadcast data to other apps like Garmin watch</string>
</resources>