optimize SetupWizard

This commit is contained in:
Milos Kozak 2022-11-15 19:28:21 +01:00
parent a5c06513e4
commit ae3650793f
6 changed files with 91 additions and 59 deletions

View file

@ -9,10 +9,7 @@ import androidx.appcompat.app.AppCompatActivity
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDeviceStatusChange
import info.nightscout.androidaps.plugins.pump.omnipod.dash.OmnipodDashPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.setupwizard.elements.SWBreak
import info.nightscout.androidaps.setupwizard.elements.SWButton
import info.nightscout.androidaps.setupwizard.elements.SWEditEncryptedPassword
@ -32,16 +29,20 @@ import info.nightscout.interfaces.AndroidPermission
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.ConfigBuilder
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.aps.Loop
import info.nightscout.interfaces.constraints.Objectives
import info.nightscout.interfaces.maintenance.ImportExportPrefs
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.OmnipodDash
import info.nightscout.interfaces.pump.OmnipodEros
import info.nightscout.interfaces.queue.CommandQueue
import info.nightscout.interfaces.ui.ActivityNames
import info.nightscout.interfaces.utils.HardLimits
import info.nightscout.plugins.constraints.objectives.ObjectivesFragment
import info.nightscout.plugins.constraints.objectives.ObjectivesPlugin
import info.nightscout.plugins.profile.ProfileFragment
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.rx.bus.RxBus
@ -49,16 +50,15 @@ import info.nightscout.rx.events.EventPumpStatusChanged
import info.nightscout.rx.events.EventSWUpdate
import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.ui.dialogs.ProfileSwitchDialog
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SWDefinition @Inject constructor(
injector: HasAndroidInjector,
private val injector: HasAndroidInjector,
private val rxBus: RxBus,
private val context: Context,
rh: ResourceHelper,
private val rh: ResourceHelper,
private val sp: SP,
private val profileFunction: ProfileFunction,
private val profilePlugin: ProfilePlugin,
@ -66,18 +66,24 @@ class SWDefinition @Inject constructor(
private val commandQueue: CommandQueue,
private val objectivesPlugin: ObjectivesPlugin,
private val configBuilder: ConfigBuilder,
private val loopPlugin: LoopPlugin,
private val loop: Loop,
private val importExportPrefs: ImportExportPrefs,
private val androidPermission: AndroidPermission,
private val cryptoUtil: CryptoUtil,
private val config: Config,
private val hardLimits: HardLimits
private val hardLimits: HardLimits,
private val activityNames: ActivityNames
) {
lateinit var activity: AppCompatActivity
private val screens: MutableList<SWScreen> = ArrayList()
private val screens: MutableList<SWScreen> = ArrayList()
fun getScreens(): List<SWScreen> {
if (screens.isEmpty()) {
if (config.APS) swDefinitionFull()
else if (config.PUMPCONTROL) swDefinitionPumpControl()
else if (config.NSCLIENT) swDefinitionNSClient()
}
return screens
}
@ -86,12 +92,12 @@ class SWDefinition @Inject constructor(
return this
}
private val screenSetupWizard = SWScreen(injector, R.string.nav_setupwizard)
private val screenSetupWizard get() = SWScreen(injector, R.string.nav_setupwizard)
.add(
SWInfoText(injector)
.label(R.string.welcometosetupwizard)
)
private val screenEula = SWScreen(injector, R.string.end_user_license_agreement)
private val screenEula get() = SWScreen(injector, R.string.end_user_license_agreement)
.skippable(false)
.add(
SWInfoText(injector)
@ -107,7 +113,8 @@ class SWDefinition @Inject constructor(
})
.visibility { !sp.getBoolean(R.string.key_i_understand, false) }
.validator { sp.getBoolean(R.string.key_i_understand, false) }
private val screenUnits = SWScreen(injector, R.string.units)
private val screenUnits get() = SWScreen(injector, R.string.units)
.skippable(false)
.add(
SWRadioButton(injector)
@ -116,7 +123,8 @@ class SWDefinition @Inject constructor(
.comment(R.string.setupwizard_units_prompt)
)
.validator { sp.contains(R.string.key_units) }
private val displaySettings = SWScreen(injector, R.string.wear_display_settings)
private val displaySettings get() = SWScreen(injector, R.string.wear_display_settings)
.skippable(false)
.add(
SWEditNumberWithUnits(injector, Constants.LOW_MARK * Constants.MGDL_TO_MMOLL, 3.0, 8.0)
@ -133,7 +141,8 @@ class SWDefinition @Inject constructor(
.label(R.string.high_mark)
.comment(R.string.high_mark_comment)
)
private val screenPermissionWindow = SWScreen(injector, R.string.permission)
private val screenPermissionWindow get() = SWScreen(injector, R.string.permission)
.skippable(false)
.add(
SWInfoText(injector)
@ -146,7 +155,8 @@ class SWDefinition @Inject constructor(
.action { activity.startActivity(Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + activity.packageName))) })
.visibility { !Settings.canDrawOverlays(activity) }
.validator { Settings.canDrawOverlays(activity) }
private val screenPermissionBattery = SWScreen(injector, R.string.permission)
private val screenPermissionBattery get() = SWScreen(injector, R.string.permission)
.skippable(false)
.add(
SWInfoText(injector)
@ -159,7 +169,8 @@ class SWDefinition @Inject constructor(
.action { androidPermission.askForPermission(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) }
private val screenPermissionBt = SWScreen(injector, R.string.permission)
private val screenPermissionBt get() = SWScreen(injector, R.string.permission)
.skippable(false)
.add(
SWInfoText(injector)
@ -172,7 +183,8 @@ class SWDefinition @Inject constructor(
.action { androidPermission.askForPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) })
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) }
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) }
private val screenPermissionStore = SWScreen(injector, R.string.permission)
private val screenPermissionStore get() = SWScreen(injector, R.string.permission)
.skippable(false)
.add(
SWInfoText(injector)
@ -185,7 +197,8 @@ class SWDefinition @Inject constructor(
.action { androidPermission.askForPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
.visibility { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
.validator { !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
private val screenImport = SWScreen(injector, R.string.nav_import)
private val screenImport get() = SWScreen(injector, R.string.nav_import)
.add(
SWInfoText(injector)
.label(R.string.storedsettingsfound)
@ -195,7 +208,8 @@ class SWDefinition @Inject constructor(
.text(R.string.nav_import)
.action { importExportPrefs.importSharedPreferences(activity) })
.visibility { importExportPrefs.prefsFileExists() && !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) }
private val screenNsClient = SWScreen(injector, R.string.configbuilder_sync)
private val screenNsClient get() = SWScreen(injector, R.string.configbuilder_sync)
.skippable(true)
.add(
SWPlugin(injector, this)
@ -215,7 +229,8 @@ class SWDefinition @Inject constructor(
.initialStatus(activePlugin.firstActiveSync?.status ?: "")
)
.validator { activePlugin.firstActiveSync?.connected == true && activePlugin.firstActiveSync?.hasWritePermission == true }
private val screenPatientName = SWScreen(injector, R.string.patient_name)
private val screenPatientName get() = SWScreen(injector, R.string.patient_name)
.skippable(true)
.add(
SWInfoText(injector)
@ -226,7 +241,8 @@ class SWDefinition @Inject constructor(
.validator(SWTextValidator(String::isNotEmpty))
.preferenceId(R.string.key_patient_name)
)
private val privacy = SWScreen(injector, R.string.privacy_settings)
private val privacy get() = SWScreen(injector, R.string.privacy_settings)
.skippable(true)
.add(
SWInfoText(injector)
@ -236,7 +252,8 @@ class SWDefinition @Inject constructor(
SWPreference(injector, this)
.option(R.xml.pref_datachoices)
)
private val screenMasterPassword = SWScreen(injector, R.string.master_password)
private val screenMasterPassword get() = SWScreen(injector, R.string.master_password)
.skippable(false)
.add(
SWInfoText(injector)
@ -252,7 +269,8 @@ class SWDefinition @Inject constructor(
.label(R.string.master_password_summary)
)
.validator { !cryptoUtil.checkPassword("", sp.getString(R.string.key_master_password, "")) }
private val screenAge = SWScreen(injector, R.string.patientage)
private val screenAge get() = SWScreen(injector, R.string.patientage)
.skippable(false)
.add(SWBreak(injector))
.add(
@ -282,7 +300,8 @@ class SWDefinition @Inject constructor(
&& sp.getDouble(R.string.key_treatmentssafety_maxbolus, 0.0) > 0
&& sp.getInt(R.string.key_treatmentssafety_maxcarbs, 0) > 0
}
private val screenInsulin = SWScreen(injector, R.string.configbuilder_insulin)
private val screenInsulin get() = SWScreen(injector, R.string.configbuilder_insulin)
.skippable(false)
.add(
SWPlugin(injector, this)
@ -295,7 +314,8 @@ class SWDefinition @Inject constructor(
SWInfoText(injector)
.label(R.string.diawarning)
)
private val screenBgSource = SWScreen(injector, R.string.configbuilder_bgsource)
private val screenBgSource get() = SWScreen(injector, R.string.configbuilder_bgsource)
.skippable(false)
.add(
SWPlugin(injector, this)
@ -303,18 +323,21 @@ class SWDefinition @Inject constructor(
.label(R.string.configbuilder_bgsource)
)
.add(SWBreak(injector))
private val screenLocalProfile = SWScreen(injector, R.string.localprofile)
private val screenLocalProfile get() = SWScreen(injector, R.string.localprofile)
.skippable(false)
.add(
SWFragment(injector, this)
.add(ProfileFragment())
.add(activity.supportFragmentManager.fragmentFactory.instantiate(ClassLoader.getSystemClassLoader(), (activePlugin.activeProfileSource as PluginBase).pluginDescription.fragmentClass!!))
//.add(ProfileFragment())
)
.validator {
profilePlugin.profile?.getDefaultProfile()?.let { ProfileSealed.Pure(it).isValid("StartupWizard", activePlugin.activePump, config, rh, rxBus, hardLimits, false).isValid }
?: false
}
.visibility { profilePlugin.isEnabled() }
private val screenProfileSwitch = SWScreen(injector, R.string.careportal_profileswitch)
private val screenProfileSwitch get() = SWScreen(injector, R.string.careportal_profileswitch)
.skippable(false)
.add(
SWInfoText(injector)
@ -322,10 +345,11 @@ class SWDefinition @Inject constructor(
)
.add(SWButton(injector)
.text(R.string.doprofileswitch)
.action { ProfileSwitchDialog().show(activity.supportFragmentManager, "ProfileSwitchDialog") })
.action { activityNames.runProfileSwitchDialog(activity.supportFragmentManager) })
.validator { profileFunction.getRequestedProfile() != null }
.visibility { profileFunction.getRequestedProfile() == null }
private val screenPump = SWScreen(injector, R.string.configbuilder_pump)
private val screenPump get() = SWScreen(injector, R.string.configbuilder_pump)
.skippable(false)
.add(
SWPlugin(injector, this)
@ -341,22 +365,22 @@ class SWDefinition @Inject constructor(
.label(R.string.setupwizard_pump_waiting_for_riley_link_connection)
.visibility {
val activePump = activePlugin.activePump
activePump is OmnipodErosPumpPlugin && !activePump.isRileyLinkReady
activePump is OmnipodEros && !activePump.isRileyLinkReady()
})
.add( // Omnipod Eros only
SWEventListener(injector, EventRileyLinkDeviceStatusChange::class.java)
.label(R.string.setupwizard_pump_riley_link_status)
.visibility { activePlugin.activePump is OmnipodErosPumpPlugin })
.visibility { activePlugin.activePump is OmnipodEros })
.add(SWButton(injector)
.text(R.string.readstatus)
.action { commandQueue.readStatus(rh.gs(R.string.clicked_connect_to_pump), null) }
.visibility {
// Hide for Omnipod, because as we don't require a Pod to be paired in the setup wizard,
// Getting the status might not be possible
activePlugin.activePump !is OmnipodErosPumpPlugin && activePlugin.activePump !is OmnipodDashPumpPlugin
activePlugin.activePump !is OmnipodEros && activePlugin.activePump !is OmnipodDash
})
.add(SWEventListener(injector, EventPumpStatusChanged::class.java)
.visibility { activePlugin.activePump !is OmnipodErosPumpPlugin && activePlugin.activePump !is OmnipodDashPumpPlugin })
.visibility { activePlugin.activePump !is OmnipodEros && activePlugin.activePump !is OmnipodDash })
.validator { isPumpInitialized() }
private fun isPumpInitialized(): Boolean {
@ -366,11 +390,11 @@ class SWDefinition @Inject constructor(
// For the Eros model, consider the pump initialized when a RL has been configured successfully
// For Dash model, consider the pump setup without any extra conditions
return activePump.isInitialized()
|| (activePump is OmnipodErosPumpPlugin && activePump.isRileyLinkReady)
|| activePump is OmnipodDashPumpPlugin
|| (activePump is OmnipodEros && activePump.isRileyLinkReady())
|| activePump is OmnipodDash
}
private val screenAps = SWScreen(injector, R.string.configbuilder_aps)
private val screenAps get() = SWScreen(injector, R.string.configbuilder_aps)
.skippable(false)
.add(
SWInfoText(injector)
@ -388,7 +412,8 @@ class SWDefinition @Inject constructor(
.label("https://openaps.readthedocs.io/en/latest/")
)
.add(SWBreak(injector))
private val screenApsMode = SWScreen(injector, R.string.apsmode_title)
private val screenApsMode get() = SWScreen(injector, R.string.apsmode_title)
.skippable(false)
.add(
SWRadioButton(injector)
@ -397,7 +422,8 @@ class SWDefinition @Inject constructor(
.comment(R.string.setupwizard_preferred_aps_mode)
)
.validator { sp.contains(R.string.key_aps_mode) }
private val screenLoop = SWScreen(injector, R.string.configbuilder_loop)
private val screenLoop get() = SWScreen(injector, R.string.configbuilder_loop)
.skippable(false)
.add(
SWInfoText(injector)
@ -407,13 +433,14 @@ class SWDefinition @Inject constructor(
.add(SWButton(injector)
.text(R.string.enableloop)
.action {
configBuilder.performPluginSwitch(loopPlugin, true, PluginType.LOOP)
configBuilder.performPluginSwitch(loop as PluginBase, true, PluginType.LOOP)
rxBus.send(EventSWUpdate(true))
}
.visibility { !loopPlugin.isEnabled() })
.validator { loopPlugin.isEnabled() }
.visibility { !loopPlugin.isEnabled() && config.APS }
private val screenSensitivity = SWScreen(injector, R.string.configbuilder_sensitivity)
.visibility { !loop.isEnabled() })
.validator { loop.isEnabled() }
.visibility { !loop.isEnabled() && config.APS }
private val screenSensitivity get() = SWScreen(injector, R.string.configbuilder_sensitivity)
.skippable(false)
.add(
SWInfoText(injector)
@ -429,7 +456,8 @@ class SWDefinition @Inject constructor(
.option(PluginType.SENSITIVITY, R.string.configbuilder_sensitivity_description)
.label(R.string.configbuilder_sensitivity)
)
private val getScreenObjectives = SWScreen(injector, R.string.objectives)
private val getScreenObjectives get() = SWScreen(injector, R.string.objectives)
.skippable(false)
.add(
SWInfoText(injector)
@ -443,7 +471,7 @@ class SWDefinition @Inject constructor(
.validator { objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].isStarted }
.visibility { !objectivesPlugin.objectives[Objectives.FIRST_OBJECTIVE].isStarted && config.APS }
private fun swDefinitionFull() { // List all the screens here
private fun swDefinitionFull() = // List all the screens here
add(screenSetupWizard)
//.add(screenLanguage)
.add(screenEula)
@ -469,9 +497,8 @@ class SWDefinition @Inject constructor(
.add(screenLoop)
.add(screenSensitivity)
.add(getScreenObjectives)
}
private fun swDefinitionPumpControl() { // List all the screens here
private fun swDefinitionPumpControl() = // List all the screens here
add(screenSetupWizard)
//.add(screenLanguage)
.add(screenEula)
@ -492,9 +519,8 @@ class SWDefinition @Inject constructor(
.add(screenProfileSwitch)
.add(screenPump)
.add(screenSensitivity)
}
private fun swDefinitionNSClient() { // List all the screens here
private fun swDefinitionNSClient() = // List all the screens here
add(screenSetupWizard)
//.add(screenLanguage)
.add(screenEula)
@ -508,9 +534,4 @@ class SWDefinition @Inject constructor(
.add(screenNsClient)
//.add(screenBgSource)
.add(screenPatientName)
}
init {
if (config.APS) swDefinitionFull() else if (config.PUMPCONTROL) swDefinitionPumpControl() else if (config.NSCLIENT) swDefinitionNSClient()
}
}

View file

@ -51,6 +51,7 @@ class SetupWizardActivity : NoSplashAppCompatActivity() {
binding = ActivitySetupwizardBinding.inflate(layoutInflater)
setContentView(binding.root)
swDefinition.activity = this
screens = swDefinition.getScreens()
val intent = intent
currentWizardPage = intent.getIntExtra(intentMessage, 0)
@ -60,7 +61,6 @@ class SetupWizardActivity : NoSplashAppCompatActivity() {
//Set screen name
val screenName = findViewById<TextView>(R.id.sw_content)
screenName.text = currentScreen.getHeader()
swDefinition.activity = this
//Generate layout first
generateLayout()
updateButtons()

View file

@ -0,0 +1,3 @@
package info.nightscout.interfaces.pump
interface OmnipodDash

View file

@ -0,0 +1,6 @@
package info.nightscout.interfaces.pump
interface OmnipodEros {
fun isRileyLinkReady(): Boolean
}

View file

@ -48,6 +48,7 @@ import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.pump.DetailedBolusInfo
import info.nightscout.interfaces.pump.OmnipodDash
import info.nightscout.interfaces.pump.Pump
import info.nightscout.interfaces.pump.PumpEnactResult
import info.nightscout.interfaces.pump.PumpPluginBase
@ -108,7 +109,7 @@ class OmnipodDashPumpPlugin @Inject constructor(
aapsLogger: AAPSLogger,
rh: ResourceHelper,
commandQueue: CommandQueue
) : PumpPluginBase(pluginDescription, injector, aapsLogger, rh, commandQueue), Pump {
) : PumpPluginBase(pluginDescription, injector, aapsLogger, rh, commandQueue), Pump, OmnipodDash {
@Volatile var bolusCanceled = false
@Volatile var bolusDeliveryInProgress = false

View file

@ -87,6 +87,7 @@ import info.nightscout.interfaces.plugin.PluginType;
import info.nightscout.interfaces.profile.Profile;
import info.nightscout.interfaces.profile.ProfileFunction;
import info.nightscout.interfaces.pump.DetailedBolusInfo;
import info.nightscout.interfaces.pump.OmnipodEros;
import info.nightscout.interfaces.pump.Pump;
import info.nightscout.interfaces.pump.PumpEnactResult;
import info.nightscout.interfaces.pump.PumpPluginBase;
@ -121,7 +122,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
* @author Andy Rozman (andy.rozman@gmail.com)
*/
@Singleton
public class OmnipodErosPumpPlugin extends PumpPluginBase implements Pump, RileyLinkPumpDevice {
public class OmnipodErosPumpPlugin extends PumpPluginBase implements Pump, RileyLinkPumpDevice, OmnipodEros {
private static final long RILEY_LINK_CONNECT_TIMEOUT_MILLIS = 3 * 60 * 1_000L; // 3 minutes
private static final long STATUS_CHECK_INTERVAL_MILLIS = 60 * 1_000L; // 1 minute
public static final int STARTUP_STATUS_REQUEST_TRIES = 2;