From 450f4fabf0cbafd5329134879dbd86e9271fae36 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 8 Oct 2019 21:20:04 +0200 Subject: [PATCH 001/153] Survey --- app/build.gradle | 2 + app/google-services.json | 28 ++- app/src/main/AndroidManifest.xml | 1 + .../nightscout/androidaps/MainActivity.java | 4 + .../androidaps/activities/SurveyActivity.kt | 115 ++++++++++++ .../nightscout/androidaps/data/Profile.java | 2 +- .../data/defaultProfile/DefaultProfile.kt | 145 +++++++++++++++ .../androidaps/db/DatabaseHelper.java | 11 +- .../info/nightscout/androidaps/db/TDD.java | 6 + .../plugins/treatments/TreatmentsPlugin.java | 68 ++++--- .../fragments/ProfileViewerDialog.kt | 23 ++- .../TreatmentsProfileSwitchFragment.java | 5 +- .../info/nightscout/androidaps/utils/TIR.kt | 5 + .../androidaps/utils/TddCalculator.kt | 70 ++++++++ .../androidaps/utils/TirCalculator.kt | 9 + app/src/main/res/layout/survey_fragment.xml | 168 ++++++++++++++++++ app/src/main/res/menu/menu_main.xml | 4 + app/src/main/res/values/strings.xml | 12 ++ .../data/defaultProfile/DefaultProfileTest.kt | 26 +++ 19 files changed, 658 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/activities/SurveyActivity.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/utils/TIR.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt create mode 100644 app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt create mode 100644 app/src/main/res/layout/survey_fragment.xml create mode 100644 app/src/test/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfileTest.kt diff --git a/app/build.gradle b/app/build.gradle index 8b2c15a042..097c8ebb5c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -226,6 +226,8 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.google.android.gms:play-services-wearable:17.0.0' implementation 'com.google.firebase:firebase-core:17.2.0' + implementation 'com.google.firebase:firebase-auth:19.1.0' + implementation 'com.google.firebase:firebase-database:19.1.0' implementation("com.crashlytics.sdk.android:crashlytics:2.9.9@aar") { transitive = true; } diff --git a/app/google-services.json b/app/google-services.json index 42db6f4289..507c792c93 100644 --- a/app/google-services.json +++ b/app/google-services.json @@ -13,7 +13,12 @@ "package_name": "info.nightscout.aapspumpcontrol" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" @@ -37,7 +42,12 @@ "package_name": "info.nightscout.androidaps" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" @@ -61,7 +71,12 @@ "package_name": "info.nightscout.nsclient" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" @@ -85,7 +100,12 @@ "package_name": "info.nightscout.nsclient2" } }, - "oauth_client": [], + "oauth_client": [ + { + "client_id": "477603612366-a925drvlvs7qn7gt73r585erbqto8c79.apps.googleusercontent.com", + "client_type": 3 + } + ], "api_key": [ { "current_key": "AIzaSyDcZpDRMaGjdhihXp531cVYM6LkEL8KbgM" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index aeeb53475d..062a67f101 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,6 +76,7 @@ + + profileList = profileStore?.profileList ?: return + val adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList) + survey_spinner.adapter = adapter + + val tdds = TddCalculator.calculate(7) + val averageTdd = TddCalculator.averageTDD(tdds) + survey_tdds.text = MainApp.gs(R.string.tdd) + ":\n" + TddCalculator.toText(tdds) + MainApp.gs(R.string.average) + ":\n" + TddCalculator.toText(averageTdd) + + survey_profile.setOnClickListener { + val age = SafeParse.stringToDouble(survey_age.text.toString()) + val weight = SafeParse.stringToDouble(survey_weight.text.toString()) + val tdd = SafeParse.stringToDouble(survey_tdd.text.toString()) + if (age < 1 || age > 120) { + ToastUtils.showToastInUiThread(this, R.string.invalidage) + return@setOnClickListener + } + if ((weight < 5 || weight > 150) && tdd == 0.0) { + ToastUtils.showToastInUiThread(this, R.string.invalidweight) + return@setOnClickListener + } + if ((tdd < 5 || tdd > 150) && weight == 0.0) { + ToastUtils.showToastInUiThread(this, R.string.invalidweight) + return@setOnClickListener + } + val profile = DefaultProfile().profile(age, tdd, weight, ProfileFunctions.getInstance().profileUnits) + val args = Bundle() + args.putLong("time", DateUtil.now()) + args.putInt("mode", ProfileViewerDialog.Mode.CUSTOM_PROFILE.ordinal) + args.putString("customProfile", profile.data.toString()) + args.putString("customProfileUnits", profile.units) + args.putString("customProfileName", "Age: $age TDD: $tdd Weight: $weight") + val pvd = ProfileViewerDialog() + pvd.arguments = args + pvd.show(supportFragmentManager, "ProfileViewDialog") + } + + survey_submit.setOnClickListener { + val r = FirebaseRecord() + r.id = InstanceId.instanceId() + r.age = SafeParse.stringToInt(survey_age.text.toString()) + r.weight = SafeParse.stringToInt(survey_weight.text.toString()) + if (r.age < 1 || r.age > 120) { + ToastUtils.showToastInUiThread(this, R.string.invalidage) + return@setOnClickListener + } + if (r.weight < 5 || r.weight > 150) { + ToastUtils.showToastInUiThread(this, R.string.invalidweight) + return@setOnClickListener + } + + if (survey_spinner.selectedItem == null) + return@setOnClickListener + val profileName = survey_spinner.selectedItem.toString() + val specificProfile = profileStore.getSpecificProfile(profileName) + + r.profileJson = specificProfile.toString() + + val auth = FirebaseAuth.getInstance() + auth.signInAnonymously() + .addOnCompleteListener(this) { task -> + if (task.isSuccessful) { + log.debug("signInAnonymously:success") + val user = auth.currentUser + + val database = FirebaseDatabase.getInstance().reference + database.child("survey").child(r.id).setValue(r) + } else { + log.error("signInAnonymously:failure", task.exception) + ToastUtils.showToastInUiThread(this, "Authentication failed.") + //updateUI(null) + } + + // ... + } + finish() + } + } + + inner class FirebaseRecord { + var id = "" + var age: Int = 0 + var weight: Int = 0 + var profileJson = "ghfg" + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java index 6f18ba7af5..1b183e2d08 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java @@ -393,7 +393,7 @@ public class Profile { return getIsfTimeFromMidnight(secondsFromMidnight(time)); } - double getIsfTimeFromMidnight(int timeAsSeconds) { + public double getIsfTimeFromMidnight(int timeAsSeconds) { if (isf_v == null) isf_v = convertToSparseArray(isf); return getValueToTime(isf_v, timeAsSeconds); diff --git a/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt new file mode 100644 index 0000000000..b121dbee02 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/data/defaultProfile/DefaultProfile.kt @@ -0,0 +1,145 @@ +package info.nightscout.androidaps.data.defaultProfile + +import info.nightscout.androidaps.data.Profile +import info.nightscout.androidaps.utils.Round +import org.json.JSONArray +import org.json.JSONObject +import java.util.* + + +class DefaultProfile { + var oneToFive: TreeMap> = TreeMap() + var sixToEleven: TreeMap> = TreeMap() + var twelveToSeventeen: TreeMap> = TreeMap() + var eighteenToTwentyfor: TreeMap> = TreeMap() + + fun profile(age: Double, tdd: Double, weight: Double, units: String): Profile { + val profile = JSONObject() + if (age >= 1 && age < 6) { + val _tdd = if (tdd == 0.0) 0.6 * weight else tdd + closest(oneToFive, _tdd * 0.3)?.let { array -> profile.put("basal", arrayToJson(array)) } + val ic = Round.roundTo(250.0 / _tdd, 1.0) + profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -4.0, -1.0, -2.0, -4.0, 0.0, -4.0))) + val isf = Round.roundTo(200.0 / _tdd, 0.1) + profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -2.0, -0.0, -0.0, -2.0, 0.0, -2.0))) + } else if (age >= 6 && age < 12) { + val _tdd = if (tdd == 0.0) 0.8 * weight else tdd + closest(sixToEleven, _tdd * 0.4)?.let { array -> profile.put("basal", arrayToJson(array)) } + val ic = Round.roundTo(375.0 / _tdd, 1.0) + profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -3.0, 0.0, -1.0, -3.0, 0.0, -2.0))) + val isf = Round.roundTo(170.0 / _tdd, 0.1) + profile.put("sens", singleValueArray(isf, arrayOf( 0.0, -1.0, -0.0, -0.0, -1.0, 0.0, -1.0))) + } else if (age >= 12 && age < 17) { + val _tdd = if (tdd == 0.0) 1.0 * weight else tdd + closest(twelveToSeventeen, _tdd * 0.5)?.let { array -> profile.put("basal", arrayToJson(array)) } + val ic = Round.roundTo(500.0 / _tdd, 1.0) + profile.put("carbratio", singleValueArray(ic, arrayOf( 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, -1.0))) + val isf = Round.roundTo(100.0 / _tdd, 0.1) + profile.put("sens", singleValueArray(isf, arrayOf( 0.2, 0.0, 0.2, 0.2, 0.0, 0.2, 0.2))) + } else if (age >= 18) { + + } + profile.put("dia", 5.0) + profile.put("carbs_hr", 20) // not used + profile.put("delay", 5.0) // not used + profile.put("timezone", TimeZone.getDefault().getID()) + profile.put("target_high", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units)))) + profile.put("target_low", JSONArray().put(JSONObject().put("time", "00:00").put("value", Profile.fromMgdlToUnits(108.0, units)))) + return Profile(profile, units) + } + + init { + oneToFive[1.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050) + oneToFive[1.13] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050) + oneToFive[1.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050) + oneToFive[1.38] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050) + oneToFive[1.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.075, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.050, 0.050, 0.050, 0.075, 0.100, 0.100, 0.050, 0.050) + oneToFive[1.75] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.050, 0.050, 0.050, 0.060, 0.060, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050) + oneToFive[2.00] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.075, 0.050, 0.050, 0.065, 0.065, 0.075, 0.075, 0.050, 0.050, 0.050, 0.100, 0.125, 0.100, 0.050, 0.050) + oneToFive[2.25] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.100, 0.100, 0.075, 0.060, 0.060, 0.070, 0.070, 0.100, 0.100, 0.050, 0.050, 0.050, 0.125, 0.150, 0.125, 0.065, 0.050) + oneToFive[2.50] = arrayOf(0.050, 0.050, 0.050, 0.050, 0.075, 0.075, 0.100, 0.125, 0.125, 0.100, 0.065, 0.065, 0.075, 0.075, 0.125, 0.125, 0.060, 0.060, 0.060, 0.150, 0.150, 0.150, 0.070, 0.060) + oneToFive[2.75] = arrayOf(0.075, 0.075, 0.075, 0.100, 0.100, 0.100, 0.125, 0.150, 0.125, 0.100, 0.070, 0.070, 0.080, 0.080, 0.150, 0.150, 0.070, 0.070, 0.070, 0.175, 0.175, 0.175, 0.080, 0.070) + oneToFive[3.25] = arrayOf(0.100, 0.100, 0.100, 0.125, 0.125, 0.125, 0.150, 0.150, 0.150, 0.100, 0.080, 0.080, 0.100, 0.100, 0.175, 0.175, 0.075, 0.075, 0.075, 0.200, 0.200, 0.200, 0.090, 0.080) + oneToFive[3.75] = arrayOf(0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.175, 0.175, 0.175, 0.100, 0.085, 0.085, 0.110, 0.110, 0.185, 0.185, 0.080, 0.080, 0.080, 0.225, 0.225, 0.225, 0.100, 0.090) + oneToFive[4.25] = arrayOf(0.125, 0.125, 0.130, 0.140, 0.140, 0.140, 0.200, 0.200, 0.200, 0.125, 0.090, 0.090, 0.120, 0.120, 0.200, 0.200, 0.100, 0.100, 0.100, 0.250, 0.250, 0.250, 0.125, 0.100) + oneToFive[4.75] = arrayOf(0.125, 0.130, 0.135, 0.150, 0.150, 0.150, 0.200, 0.225, 0.200, 0.125, 0.100, 0.100, 0.125, 0.125, 0.250, 0.200, 0.110, 0.125, 0.125, 0.275, 0.275, 0.275, 0.130, 0.125) + oneToFive[5.25] = arrayOf(0.150, 0.150, 0.150, 0.170, 0.170, 0.170, 0.225, 0.225, 0.225, 0.130, 0.125, 0.125, 0.140, 0.140, 0.250, 0.250, 0.150, 0.150, 0.150, 0.300, 0.300, 0.300, 0.150, 0.150) + oneToFive[6.00] = arrayOf(0.170, 0.170, 0.175, 0.200, 0.200, 0.200, 0.250, 0.250, 0.250, 0.150, 0.125, 0.125, 0.150, 0.150, 0.275, 0.275, 0.170, 0.150, 0.150, 0.350, 0.350, 0.350, 0.175, 0.150) + oneToFive[6.75] = arrayOf(0.200, 0.200, 0.200, 0.225, 0.225, 0.225, 0.275, 0.275, 0.275, 0.200, 0.130, 0.130, 0.175, 0.175, 0.300, 0.300, 0.170, 0.175, 0.175, 0.375, 0.375, 0.375, 0.200, 0.175) + oneToFive[7.50] = arrayOf(0.225, 0.230, 0.235, 0.250, 0.250, 0.250, 0.300, 0.300, 0.300, 0.250, 0.150, 0.150, 0.200, 0.200, 0.325, 0.325, 0.200, 0.200, 0.200, 0.400, 0.450, 0.400, 0.350, 0.200) + + sixToEleven[5.26] = arrayOf(0.18, 0.18, 0.18, 0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.18, 0.15, 0.13, 0.15, 0.15, 0.25, 0.25, 0.20, 0.15, 0.18, 0.25, 0.25, 0.25, 0.23, 0.20) + sixToEleven[5.61] = arrayOf(0.18, 0.20, 0.20, 0.23, 0.23, 0.25, 0.28, 0.28, 0.25, 0.20, 0.15, 0.13, 0.15, 0.18, 0.25, 0.25, 0.20, 0.15, 0.18, 0.28, 0.25, 0.25, 0.23, 0.20) + sixToEleven[5.93] = arrayOf(0.20, 0.20, 0.23, 0.25, 0.25, 0.25, 0.30, 0.30, 0.30, 0.25, 0.15, 0.15, 0.18, 0.18, 0.28, 0.28, 0.20, 0.20, 0.20, 0.28, 0.28, 0.28, 0.25, 0.23) + sixToEleven[6.26] = arrayOf(0.20, 0.23, 0.23, 0.25, 0.25, 0.28, 0.33, 0.30, 0.30, 0.25, 0.18, 0.15, 0.18, 0.18, 0.28, 0.28, 0.23, 0.20, 0.20, 0.28, 0.30, 0.28, 0.25, 0.23) + sixToEleven[6.60] = arrayOf(0.23, 0.23, 0.25, 0.25, 0.25, 0.28, 0.33, 0.33, 0.33, 0.28, 0.18, 0.15, 0.18, 0.18, 0.30, 0.28, 0.23, 0.23, 0.20, 0.30, 0.30, 0.30, 0.25, 0.25) + sixToEleven[7.26] = arrayOf(0.23, 0.25, 0.28, 0.28, 0.30, 0.33, 0.38, 0.35, 0.35, 0.30, 0.18, 0.18, 0.18, 0.19, 0.33, 0.30, 0.25, 0.23, 0.23, 0.33, 0.33, 0.33, 0.30, 0.25) + sixToEleven[7.92] = arrayOf(0.25, 0.25, 0.28, 0.30, 0.33, 0.35, 0.38, 0.38, 0.38, 0.35, 0.20, 0.20, 0.23, 0.25, 0.35, 0.33, 0.30, 0.25, 0.25, 0.35, 0.35, 0.35, 0.33, 0.28) + sixToEleven[8.57] = arrayOf(0.28, 0.28, 0.30, 0.30, 0.33, 0.38, 0.40, 0.43, 0.40, 0.38, 0.25, 0.25, 0.25, 0.28, 0.38, 0.38, 0.33, 0.28, 0.28, 0.38, 0.40, 0.38, 0.35, 0.30) + sixToEleven[9.24] = arrayOf(0.30, 0.33, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.43, 0.40, 0.30, 0.25, 0.28, 0.28, 0.38, 0.40, 0.33, 0.30, 0.30, 0.40, 0.43, 0.40, 0.38, 0.35) + sixToEleven[9.89] = arrayOf(0.35, 0.35, 0.38, 0.40, 0.40, 0.43, 0.45, 0.48, 0.45, 0.40, 0.30, 0.25, 0.28, 0.30, 0.40, 0.43, 0.35, 0.33, 0.33, 0.43, 0.45, 0.43, 0.40, 0.38) + sixToEleven[10.56] = arrayOf(0.38, 0.38, 0.40, 0.43, 0.45, 0.45, 0.48, 0.50, 0.48, 0.40, 0.35, 0.25, 0.30, 0.33, 0.43, 0.45, 0.35, 0.35, 0.35, 0.45, 0.48, 0.45, 0.43, 0.40) + sixToEleven[11.21] = arrayOf(0.40, 0.43, 0.43, 0.45, 0.48, 0.50, 0.53, 0.55, 0.50, 0.40, 0.35, 0.30, 0.33, 0.33, 0.45, 0.48, 0.38, 0.35, 0.37, 0.50, 0.50, 0.48, 0.45, 0.43) + sixToEleven[11.88] = arrayOf(0.43, 0.43, 0.45, 0.45, 0.48, 0.50, 0.55, 0.58, 0.50, 0.40, 0.35, 0.33, 0.33, 0.33, 0.48, 0.50, 0.40, 0.38, 0.38, 0.53, 0.53, 0.50, 0.48, 0.45) + sixToEleven[12.53] = arrayOf(0.45, 0.45, 0.48, 0.50, 0.53, 0.55, 0.60, 0.60, 0.60, 0.45, 0.40, 0.35, 0.35, 0.38, 0.50, 0.53, 0.40, 0.38, 0.38, 0.55, 0.58, 0.55, 0.50, 0.48) + sixToEleven[13.19] = arrayOf(0.48, 0.48, 0.50, 0.55, 0.58, 0.60, 0.65, 0.65, 0.65, 0.50, 0.45, 0.36, 0.38, 0.40, 0.55, 0.55, 0.45, 0.40, 0.40, 0.60, 0.60, 0.58, 0.55, 0.50) + sixToEleven[14.18] = arrayOf(0.53, 0.53, 0.55, 0.60, 0.65, 0.68, 0.70, 0.70, 0.68, 0.60, 0.55, 0.40, 0.40, 0.45, 0.60, 0.60, 0.50, 0.45, 0.45, 0.63, 0.65, 0.63, 0.60, 0.60) + sixToEleven[15.17] = arrayOf(0.55, 0.58, 0.60, 0.65, 0.70, 0.70, 0.75, 0.75, 0.70, 0.65, 0.60, 0.42, 0.42, 0.45, 0.65, 0.65, 0.60, 0.50, 0.50, 0.68, 0.68, 0.65, 0.63, 0.63) + sixToEleven[16.50] = arrayOf(0.60, 0.63, 0.65, 0.70, 0.70, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.45, 0.45, 0.50, 0.65, 0.70, 0.60, 0.55, 0.55, 0.75, 0.75, 0.70, 0.65, 0.65) + + twelveToSeventeen[10.70] = arrayOf(0.30, 0.30, 0.30, 0.30, 0.40, 0.40, 0.60, 0.60, 0.60, 0.40, 0.35, 0.30, 0.30, 0.35, 0.45, 0.50, 0.40, 0.30, 0.30, 0.40, 0.50, 0.40, 0.40, 0.30) + twelveToSeventeen[11.10] = arrayOf(0.30, 0.30, 0.30, 0.35, 0.40, 0.45, 0.60, 0.60, 0.60, 0.40, 0.40, 0.30, 0.35, 0.40, 0.50, 0.50, 0.30, 0.30, 0.30, 0.50, 0.50, 0.50, 0.30, 0.30) + twelveToSeventeen[11.60] = arrayOf(0.30, 0.30, 0.35, 0.45, 0.45, 0.50, 0.65, 0.65, 0.65, 0.45, 0.40, 0.40, 0.40, 0.40, 0.50, 0.55, 0.55, 0.45, 0.45, 0.50, 0.50, 0.50, 0.40, 0.40) + twelveToSeventeen[13.00] = arrayOf(0.40, 0.40, 0.40, 0.50, 0.55, 0.60, 0.70, 0.70, 0.70, 0.60, 0.50, 0.40, 0.40, 0.40, 0.50, 0.60, 0.60, 0.50, 0.50, 0.60, 0.60, 0.60, 0.40, 0.30) + twelveToSeventeen[15.60] = arrayOf(0.45, 0.50, 0.50, 0.60, 0.65, 0.70, 0.80, 0.80, 0.80, 0.70, 0.60, 0.60, 0.50, 0.50, 0.60, 0.70, 0.70, 0.60, 0.60, 0.60, 0.70, 0.70, 0.50, 0.50) + twelveToSeventeen[17.00] = arrayOf(0.50, 0.55, 0.60, 0.70, 0.75, 0.80, 1.00, 1.00, 1.00, 0.80, 0.70, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.65, 0.65, 0.65, 0.70, 0.70, 0.60, 0.60) + twelveToSeventeen[18.00] = arrayOf(0.60, 0.65, 0.70, 0.80, 0.85, 0.90, 1.10, 1.10, 1.10, 0.90, 0.80, 0.60, 0.60, 0.60, 0.70, 0.80, 0.80, 0.70, 0.65, 0.70, 0.75, 0.70, 0.60, 0.60) + twelveToSeventeen[20.20] = arrayOf(0.70, 0.75, 0.80, 0.90, 0.95, 1.00, 1.10, 1.10, 1.10, 0.90, 0.80, 0.70, 0.70, 0.70, 0.80, 0.90, 0.90, 0.75, 0.75, 0.75, 0.80, 0.80, 0.70, 0.70) + twelveToSeventeen[21.60] = arrayOf(0.75, 0.80, 0.90, 0.90, 1.00, 1.00, 1.20, 1.20, 1.20, 0.90, 0.80, 0.70, 0.70, 0.70, 0.90, 1.00, 1.00, 0.80, 0.80, 0.80, 0.80, 0.80, 0.70, 0.70) + twelveToSeventeen[23.80] = arrayOf(0.75, 0.80, 0.90, 1.00, 1.10, 1.10, 1.20, 1.20, 1.20, 1.00, 0.90, 0.80, 0.80, 0.80, 0.90, 1.10, 1.10, 0.90, 0.90, 0.90, 1.00, 1.00, 0.80, 0.80) + twelveToSeventeen[26.10] = arrayOf(0.80, 0.80, 0.90, 1.00, 1.20, 1.20, 1.30, 1.30, 1.30, 1.10, 1.00, 0.90, 0.90, 0.90, 1.00, 1.20, 1.10, 0.90, 0.90, 1.00, 1.00, 1.00, 0.90, 0.90) + twelveToSeventeen[28.00] = arrayOf(0.90, 0.90, 1.00, 1.10, 1.10, 1.20, 1.30, 1.30, 1.30, 1.20, 1.00, 1.00, 1.00, 1.00, 1.20, 1.20, 1.20, 1.00, 1.00, 1.10, 1.10, 1.10, 0.90, 0.90) + twelveToSeventeen[30.10] = arrayOf(1.00, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.50, 1.50, 1.30, 1.20, 1.00, 1.00, 1.00, 1.30, 1.40, 1.40, 1.00, 1.00, 1.15, 1.15, 1.10, 1.00, 1.00) + twelveToSeventeen[32.60] = arrayOf(1.10, 1.10, 1.20, 1.20, 1.40, 1.50, 1.50, 1.50, 1.50, 1.30, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.40, 1.10, 1.10, 1.20, 1.20, 1.20, 1.10, 1.10) + twelveToSeventeen[35.20] = arrayOf(1.20, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.70, 1.50, 1.40, 1.20, 1.10, 1.10, 1.10, 1.40, 1.50, 1.60, 1.40, 1.20, 1.20, 1.30, 1.30, 1.20, 1.20) + twelveToSeventeen[39.00] = arrayOf(1.30, 1.30, 1.40, 1.60, 1.60, 1.60, 1.90, 1.90, 1.90, 1.50, 1.30, 1.20, 1.20, 1.30, 1.50, 1.60, 1.70, 1.80, 1.50, 1.50, 1.60, 1.60, 1.30, 1.30) + twelveToSeventeen[42.80] = arrayOf(1.40, 1.40, 1.50, 1.70, 1.80, 1.80, 2.00, 2.00, 2.00, 1.80, 1.80, 1.50, 1.50, 1.50, 1.60, 1.70, 1.80, 1.90, 1.60, 1.60, 1.70, 1.70, 1.50, 1.50) + twelveToSeventeen[47.30] = arrayOf(1.50, 1.50, 1.70, 1.70, 2.00, 2.00, 2.20, 2.30, 2.20, 2.00, 1.80, 1.60, 1.60, 1.60, 1.80, 2.00, 2.10, 1.90, 1.80, 1.80, 2.00, 2.00, 1.60, 1.60) + } + + private fun closest(map: TreeMap>, key: Double): Array? { + val low = map.floorEntry(key) + val high = map.ceilingEntry(key) + var res: Array? = null + if (low != null && high != null) { + res = if (Math.abs(key - low.key) < Math.abs(key - high.key)) + low.value + else + high.value + } else if (low != null || high != null) { + res = if (low != null) low.value else high.value + } + return res + } + + fun arrayToJson(b: Array): JSONArray { + val basals = JSONArray() + for (i in 0..23) { + val time = String.format(Locale.ENGLISH, "%02d:00", i) + basals.put(JSONObject().put("time", time).put("value", b[i].toString())) + } + return basals + } + + fun singleValueArray(value: Double, sample: Array): JSONArray { + val array = JSONArray() + array.put(JSONObject().put("time", "00:00").put("value", value + sample[0])) + array.put(JSONObject().put("time", "06:00").put("value", value + sample[1])) + array.put(JSONObject().put("time", "09:00").put("value", value + sample[2])) + array.put(JSONObject().put("time", "11:00").put("value", value + sample[3])) + array.put(JSONObject().put("time", "14:00").put("value", value + sample[4])) + array.put(JSONObject().put("time", "16:00").put("value", value + sample[5])) + array.put(JSONObject().put("time", "19:00").put("value", value + sample[6])) + return array + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index 9fa3ab9929..20bad315e8 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -1593,14 +1593,23 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { // ---------------- ProfileSwitch handling --------------- - public List getProfileSwitchData(boolean ascending) { + public List getProfileSwitchData(long from, boolean ascending) { try { Dao daoProfileSwitch = getDaoProfileSwitch(); List profileSwitches; QueryBuilder queryBuilder = daoProfileSwitch.queryBuilder(); queryBuilder.orderBy("date", ascending); queryBuilder.limit(100L); + Where where = queryBuilder.where(); + where.ge("date", from); + queryBuilder.setCountOf(true); PreparedQuery preparedQuery = queryBuilder.prepare(); + long count = daoProfileSwitch.countOf(preparedQuery); + // now do query of count + 1 + queryBuilder = daoProfileSwitch.queryBuilder(); + queryBuilder.orderBy("date", ascending); + queryBuilder.limit(count + 1); + preparedQuery = queryBuilder.prepare(); profileSwitches = daoProfileSwitch.query(preparedQuery); return profileSwitches; } catch (SQLException e) { diff --git a/app/src/main/java/info/nightscout/androidaps/db/TDD.java b/app/src/main/java/info/nightscout/androidaps/db/TDD.java index 93a228316c..0be693c5a4 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/TDD.java +++ b/app/src/main/java/info/nightscout/androidaps/db/TDD.java @@ -6,6 +6,8 @@ import com.j256.ormlite.table.DatabaseTable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; @@ -56,4 +58,8 @@ public class TDD { ", total=" + total + ']'; } + + public String toText() { + return MainApp.gs(R.string.tddformat, total, bolus, basal); + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index 195005e87a..480a387214 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -100,11 +100,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Override protected void onStart() { MainApp.bus().register(this); - initializeTempBasalData(); - initializeTreatmentData(); - initializeExtendedBolusData(); - initializeTempTargetData(); - initializeProfileSwitchData(); + initializeData(range()); super.onStart(); } @@ -118,61 +114,61 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface return this.service; } - private void initializeTreatmentData() { + private long range() { + double dia = Constants.defaultDIA; + if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) + dia = ProfileFunctions.getInstance().getProfile().getDia(); + return (long) (60 * 60 * 1000L * (24 + dia)); + } + + public void initializeData(long range) { + initializeTempBasalData(range); + initializeTreatmentData(range); + initializeExtendedBolusData(range); + initializeTempTargetData(range); + initializeProfileSwitchData(range); + } + + private void initializeTreatmentData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeTreatmentData"); - double dia = Constants.defaultDIA; - if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) - dia = ProfileFunctions.getInstance().getProfile().getDia(); - long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); synchronized (treatments) { treatments.clear(); - treatments.addAll(getService().getTreatmentDataFromTime(fromMills, false)); + treatments.addAll(getService().getTreatmentDataFromTime(DateUtil.now() - range, false)); } } - private void initializeTempBasalData() { + private void initializeTempBasalData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeTempBasalData"); - double dia = Constants.defaultDIA; - if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) - dia = ProfileFunctions.getInstance().getProfile().getDia(); - long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); - synchronized (tempBasals) { - tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(fromMills, false)); + tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(DateUtil.now() - range, false)); } } - private void initializeExtendedBolusData() { + private void initializeExtendedBolusData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeExtendedBolusData"); - double dia = Constants.defaultDIA; - if (ConfigBuilderPlugin.getPlugin() != null && ProfileFunctions.getInstance().getProfile() != null) - dia = ProfileFunctions.getInstance().getProfile().getDia(); - long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); - synchronized (extendedBoluses) { - extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(fromMills, false)); + extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(DateUtil.now() - range, false)); } } - private void initializeTempTargetData() { + private void initializeTempTargetData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeTempTargetData"); synchronized (tempTargets) { - long fromMills = System.currentTimeMillis() - 60 * 60 * 1000L * 24; - tempTargets.reset().add(MainApp.getDbHelper().getTemptargetsDataFromTime(fromMills, false)); + tempTargets.reset().add(MainApp.getDbHelper().getTemptargetsDataFromTime(DateUtil.now() - range, false)); } } - private void initializeProfileSwitchData() { + private void initializeProfileSwitchData(long range) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("initializeProfileSwitchData"); synchronized (profiles) { - profiles.reset().add(MainApp.getDbHelper().getProfileSwitchData(false)); + profiles.reset().add(MainApp.getDbHelper().getProfileSwitchData(DateUtil.now() - range, false)); } } @@ -222,7 +218,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface if (!pumpInterface.isFakingTempsByExtendedBoluses()) synchronized (extendedBoluses) { - for (Integer pos = 0; pos < extendedBoluses.size(); pos++) { + for (int pos = 0; pos < extendedBoluses.size(); pos++) { ExtendedBolus e = extendedBoluses.get(pos); if (e.date > time) continue; IobTotal calc = e.iobCalc(time); @@ -391,8 +387,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface public void onStatusEvent(final EventReloadTreatmentData ev) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("EventReloadTreatmentData"); - initializeTreatmentData(); - initializeExtendedBolusData(); + initializeTreatmentData(range()); + initializeExtendedBolusData(range()); updateTotalIOBTreatments(); MainApp.bus().post(ev.next); } @@ -402,7 +398,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface public void onStatusEvent(final EventReloadTempBasalData ev) { if (L.isEnabled(L.DATATREATMENTS)) log.debug("EventReloadTempBasalData"); - initializeTempBasalData(); + initializeTempBasalData(range()); updateTotalIOBTempBasals(); } @@ -685,7 +681,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Subscribe @SuppressWarnings("unused") public void onStatusEvent(final EventTempTargetChange ev) { - initializeTempTargetData(); + initializeTempTargetData(range()); } @Nullable @@ -722,7 +718,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Subscribe @SuppressWarnings("unused") public void onStatusEvent(final EventReloadProfileSwitchData ev) { - initializeProfileSwitchData(); + initializeProfileSwitchData(range()); } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt index a27ebfb656..2256f6538e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/ProfileViewerDialog.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment +import info.nightscout.androidaps.Constants import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.data.Profile @@ -14,16 +15,21 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin import info.nightscout.androidaps.utils.DateUtil import kotlinx.android.synthetic.main.close.* import kotlinx.android.synthetic.main.profileviewer_fragment.* +import org.json.JSONObject class ProfileViewerDialog : DialogFragment() { private var time: Long = 0 enum class Mode(val i: Int) { RUNNING_PROFILE(1), - PUMP_PROFILE(2) + PUMP_PROFILE(2), + CUSTOM_PROFILE(3) } - private var mode: Mode = Mode.RUNNING_PROFILE; + private var mode: Mode = Mode.RUNNING_PROFILE + private var customProfileJson: String = "" + private var customProfileName: String = "" + private var customProfileUnits: String = Constants.MGDL override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -31,6 +37,9 @@ class ProfileViewerDialog : DialogFragment() { (savedInstanceState ?: arguments)?.let { bundle -> time = bundle.getLong("time", 0) mode = Mode.values()[bundle.getInt("mode", Mode.RUNNING_PROFILE.ordinal)] + customProfileJson = bundle.getString("customProfile", "") + customProfileUnits = bundle.getString("customProfileUnits", Constants.MGDL) + customProfileName = bundle.getString("customProfileName", "") } return inflater.inflate(R.layout.profileviewer_fragment, container, false) @@ -64,6 +73,13 @@ class ProfileViewerDialog : DialogFragment() { profileview_reload.visibility = View.VISIBLE profileview_datelayout.visibility = View.GONE } + Mode.CUSTOM_PROFILE -> { + profile = Profile(JSONObject(customProfileJson), customProfileUnits) + profileName = customProfileName + date = "" + profileview_reload.visibility = View.GONE + profileview_datelayout.visibility = View.GONE + } } profileview_noprofile.visibility = View.VISIBLE @@ -92,6 +108,9 @@ class ProfileViewerDialog : DialogFragment() { super.onSaveInstanceState(bundle) bundle.putLong("time", time) bundle.putInt("mode", mode.ordinal) + bundle.putString("customProfile", customProfileJson) + bundle.putString("customProfileName", customProfileName) + bundle.putString("customProfileUnits", customProfileUnits) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java index 71d8eb2b18..3b5e5bf56d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/fragments/TreatmentsProfileSwitchFragment.java @@ -40,6 +40,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DecimalFormatter; import info.nightscout.androidaps.utils.SP; +import info.nightscout.androidaps.utils.T; /** * Created by mike on 13/01/17. @@ -183,7 +184,7 @@ public class TreatmentsProfileSwitchFragment extends SubscriberFragment implemen llm = new LinearLayoutManager(view.getContext()); recyclerView.setLayoutManager(llm); - RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(false)); + RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(DateUtil.now() - T.days(30).msecs(), false)); recyclerView.setAdapter(adapter); refreshFromNS = (Button) view.findViewById(R.id.profileswitch_refreshfromnightscout); @@ -230,7 +231,7 @@ public class TreatmentsProfileSwitchFragment extends SubscriberFragment implemen activity.runOnUiThread(new Runnable() { @Override public void run() { - recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(false)), false); + recyclerView.swapAdapter(new RecyclerViewAdapter(MainApp.getDbHelper().getProfileSwitchData(DateUtil.now() - T.days(30).msecs(),false)), false); } }); } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TIR.kt b/app/src/main/java/info/nightscout/androidaps/utils/TIR.kt new file mode 100644 index 0000000000..9d0d662f5e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/TIR.kt @@ -0,0 +1,5 @@ +package info.nightscout.androidaps.utils + +class TIR(val low: Double, val high: Double) { + +} diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt new file mode 100644 index 0000000000..de71bb3e51 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/TddCalculator.kt @@ -0,0 +1,70 @@ +package info.nightscout.androidaps.utils + +import android.util.LongSparseArray +import info.nightscout.androidaps.MainApp +import info.nightscout.androidaps.R +import info.nightscout.androidaps.db.TDD +import info.nightscout.androidaps.logging.L +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import org.slf4j.LoggerFactory + +object TddCalculator : TreatmentsPlugin() { + private val log = LoggerFactory.getLogger(L.DATATREATMENTS) + + fun calculate(days: Long): LongSparseArray { + val range = T.days(days + 1).msecs() + val startTime = MidnightTime.calc(DateUtil.now()) - T.days(days).msecs() + val endTime = MidnightTime.calc(DateUtil.now()) + initializeData(range) + + + val result = LongSparseArray() + for (t in treatmentsFromHistory) { + if (!t.isValid) continue + if (t.date < startTime || t.date > endTime) continue + val midnight = MidnightTime.calc(t.date) + val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0) + tdd.bolus += t.insulin + result.put(midnight, tdd) + } + + for (t in startTime until endTime step T.mins(5).msecs()) { + val midnight = MidnightTime.calc(t) + val tdd = result[midnight] ?: TDD(midnight, 0.0, 0.0, 0.0) + val tbr = getTempBasalFromHistory(t) + val profile = ProfileFunctions.getInstance().getProfile(t) ?: continue + val absoluteRate = tbr?.tempBasalConvertedToAbsolute(t, profile) ?: profile.getBasal(t) + tdd.basal += absoluteRate / 60.0 * 5.0 + result.put(midnight, tdd) + } + for (i in 0 until result.size()) { + val tdd = result.valueAt(i) + tdd.total = tdd.bolus + tdd.basal + } + log.debug(result.toString()) + return result + } + + fun averageTDD(tdds: LongSparseArray): TDD { + val totalTdd = TDD() + for (i in 0 until tdds.size()) { + val tdd = tdds.valueAt(i) + totalTdd.basal += tdd.basal + totalTdd.bolus += tdd.bolus + totalTdd.total += tdd.total + } + totalTdd.basal /= tdds.size().toDouble() + totalTdd.bolus /= tdds.size().toDouble() + totalTdd.total /= tdds.size().toDouble() + return totalTdd + } + + fun toText(tdds: LongSparseArray) : String { + var t = "" + for (i in 0 until tdds.size()) { + t += "${tdds.valueAt(i).toText()}\n" + } + return t + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt new file mode 100644 index 0000000000..3fb4bc6fa5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/utils/TirCalculator.kt @@ -0,0 +1,9 @@ +package info.nightscout.androidaps.utils + +import android.util.LongSparseArray + +object TirCalculator { + fun calculate(days: Long): LongSparseArray { + + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/survey_fragment.xml b/app/src/main/res/layout/survey_fragment.xml new file mode 100644 index 0000000000..7032dbe803 --- /dev/null +++ b/app/src/main/res/layout/survey_fragment.xml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +