Merge branch 'dev' into aidex_support_v2
This commit is contained in:
commit
e82c6976fd
721 changed files with 11616 additions and 7511 deletions
|
@ -44,5 +44,5 @@ Hints
|
|||
* Start small, it is easier to review smaller changes that affect fewer parts of code
|
||||
* Take a look into Issues list (https://github.com/nightscout/AndroidAPS/issues) - maybe there is something you can fix or implement
|
||||
* For new features, make sure there is Issue to track progress and have on-topic discussion
|
||||
* Reach out to community, discuss idea on Gitter (https://gitter.im/MilosKozak/AndroidAPS)
|
||||
* Reach out to community, discuss idea on Discord (https://discord.gg/4fQUWHZ4Mw)
|
||||
* Speak with other developers to minimise merge conflicts. Find out who worked, working or plan to work on speciffic issue or part of app
|
||||
|
|
|
@ -109,7 +109,7 @@ android {
|
|||
defaultConfig {
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "3.0.0.1-dev-aidex"
|
||||
version "3.0.0.1-dev-i"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
|
@ -167,9 +167,6 @@ android {
|
|||
|
||||
allprojects {
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,14 +41,35 @@
|
|||
<application
|
||||
android:name=".MainApp"
|
||||
android:allowBackup="true"
|
||||
android:backupAgent=".utils.SPBackupAgent"
|
||||
android:fullBackupOnly="false"
|
||||
android:icon="${appIcon}"
|
||||
android:label="@string/app_name"
|
||||
android:restoreAnyVersion="true"
|
||||
android:roundIcon="${appIconRound}"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.Launcher"
|
||||
android:fullBackupOnly="false"
|
||||
android:backupAgent=".utils.SPBackupAgent"
|
||||
android:restoreAnyVersion="true">
|
||||
android:theme="@style/AppTheme.Launcher" >
|
||||
|
||||
<activity
|
||||
android:name=".widget.WidgetConfigureActivity"
|
||||
android:theme="@android:style/Theme.Material.Dialog.NoActionBar"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver
|
||||
android:name=".widget.Widget"
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_info" />
|
||||
</receiver>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.backup.api_key"
|
||||
|
@ -59,6 +80,7 @@
|
|||
android:resource="@xml/automotive_app_desc" />
|
||||
|
||||
<activity android:name=".MainActivity"
|
||||
android:theme="@style/AppTheme"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
@ -76,12 +98,18 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".plugins.general.maintenance.activities.PrefImportListActivity" />
|
||||
<activity android:name=".activities.HistoryBrowseActivity" />
|
||||
<activity android:name=".activities.TreatmentsActivity" />
|
||||
<activity android:name=".activities.SurveyActivity" />
|
||||
<activity android:name=".activities.ProfileHelperActivity" />
|
||||
<activity android:name=".activities.StatsActivity" />
|
||||
<activity android:name=".plugins.general.maintenance.activities.PrefImportListActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".activities.HistoryBrowseActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".activities.TreatmentsActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".activities.SurveyActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".activities.ProfileHelperActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".activities.StatsActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity
|
||||
android:name="com.google.firebase.auth.internal.FederatedSignInActivity"
|
||||
android:excludeFromRecents="true"
|
||||
|
@ -125,9 +153,6 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Receiver keep alive, scheduled every 30 min -->
|
||||
<receiver android:name=".receivers.KeepAliveReceiver" />
|
||||
|
||||
<!-- Receive ignore 5m, 15m, 30m requests for carb notifications -->
|
||||
<receiver android:name=".plugins.aps.loop.CarbSuggestionReceiver" />
|
||||
|
||||
|
@ -235,6 +260,7 @@
|
|||
<activity
|
||||
android:name=".setupwizard.SetupWizardActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@style/AppTheme"
|
||||
android:label="@string/title_activity_setup_wizard" />
|
||||
|
||||
<activity
|
||||
|
|
|
@ -202,161 +202,194 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
halfBasalTarget = 160; // when temptarget is 160 mg/dL, run 50% basal (120 = 75%; 140 = 60%)
|
||||
// 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default)
|
||||
}
|
||||
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget
|
||||
|| profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
|
||||
// w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
|
||||
// e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
|
||||
//sensitivityRatio = 2/(2+(target_bg-normalTarget)/40);
|
||||
var c = halfBasalTarget - normalTarget;
|
||||
sensitivityRatio = c/(c+target_bg-normalTarget);
|
||||
// limit sensitivityRatio to profile.autosens_max (1.2x by default)
|
||||
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
|
||||
sensitivityRatio = round(sensitivityRatio,2);
|
||||
console.log("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
||||
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||
sensitivityRatio = autosens_data.ratio;
|
||||
console.log("Autosens ratio: "+sensitivityRatio+"; ");
|
||||
}
|
||||
if (sensitivityRatio) {
|
||||
basal = profile.current_basal * sensitivityRatio;
|
||||
basal = round_basal(basal, profile);
|
||||
if (basal !== profile_current_basal) {
|
||||
console.log("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
||||
} else {
|
||||
console.log("Basal unchanged: "+basal+"; ");
|
||||
}
|
||||
}
|
||||
|
||||
// adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120
|
||||
if (profile.temptargetSet) {
|
||||
//console.log("Temp Target set, not adjusting with autosens; ");
|
||||
} else if (typeof autosens_data !== 'undefined' && autosens_data) {
|
||||
if ( profile.sensitivity_raises_target && autosens_data.ratio < 1 || profile.resistance_lowers_target && autosens_data.ratio > 1 ) {
|
||||
// with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range
|
||||
min_bg = round((min_bg - 60) / autosens_data.ratio) + 60;
|
||||
max_bg = round((max_bg - 60) / autosens_data.ratio) + 60;
|
||||
var new_target_bg = round((target_bg - 60) / autosens_data.ratio) + 60;
|
||||
// don't allow target_bg below 80
|
||||
new_target_bg = Math.max(80, new_target_bg);
|
||||
if (target_bg === new_target_bg) {
|
||||
console.log("target_bg unchanged: "+new_target_bg+"; ");
|
||||
} else {
|
||||
console.log("target_bg from "+target_bg+" to "+new_target_bg+"; ");
|
||||
}
|
||||
target_bg = new_target_bg;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof iob_data === 'undefined' ) {
|
||||
rT.error ='Error: iob_data undefined. ';
|
||||
return rT;
|
||||
}
|
||||
|
||||
var iobArray = iob_data;
|
||||
if (typeof(iob_data.length) && iob_data.length > 1) {
|
||||
iob_data = iobArray[0];
|
||||
//console.error(JSON.stringify(iob_data[0]));
|
||||
}
|
||||
|
||||
if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' ) {
|
||||
rT.error ='Error: iob_data missing some property. ';
|
||||
return rT;
|
||||
}
|
||||
|
||||
var tick;
|
||||
|
||||
if (glucose_status.delta > -0.5) {
|
||||
tick = "+" + round(glucose_status.delta,0);
|
||||
} else {
|
||||
tick = round(glucose_status.delta,0);
|
||||
}
|
||||
//var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta);
|
||||
var minAvgDelta = Math.min(glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
var maxDelta = Math.max(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
|
||||
var profile_sens = round(profile.sens,1)
|
||||
var sens = profile.sens;
|
||||
|
||||
var now = new Date().getHours();
|
||||
if (now < 1){
|
||||
now = 1;}
|
||||
else {
|
||||
console.error("Time now is "+now+"; ");
|
||||
}
|
||||
console.error(" ");
|
||||
console.error("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||
console.error("++ Dynamic ISF Beta 1.4 - Linear Extrapolation/TDD7 ++");
|
||||
console.error("++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
||||
console.error(" ");
|
||||
if (now < 1){
|
||||
now = 1;}
|
||||
else {
|
||||
console.error("Time now is "+now+"; ");
|
||||
}
|
||||
//*********************************************************************************
|
||||
//** Start of Dynamic ISF code for predictions **
|
||||
//*********************************************************************************
|
||||
|
||||
if (meal_data.TDDAIMI7){
|
||||
var tdd7 = meal_data.TDDAIMI7;
|
||||
console.error("---------------------------------------------------------");
|
||||
console.error( " Dynamic ISF version Beta 1.5 ");
|
||||
console.error("---------------------------------------------------------");
|
||||
|
||||
|
||||
if (meal_data.TDDAIMI7){
|
||||
var tdd7 = meal_data.TDDAIMI7;
|
||||
}
|
||||
else{
|
||||
var tdd7 = ((basal * 12)*100)/21;
|
||||
}
|
||||
console.error("7-day average TDD is: " +tdd7+ "; ");
|
||||
console.error(" ");
|
||||
|
||||
if (meal_data.TDDLast24){
|
||||
var tdd_24 = meal_data.TDDLast24;
|
||||
if (meal_data.TDDLast24){
|
||||
var tdd_24 = meal_data.TDDLast24;
|
||||
}
|
||||
else {
|
||||
var tdd_24 = (( basal * 24 ) * 2.8);
|
||||
}
|
||||
|
||||
if (meal_data.TDDPUMP){
|
||||
var tdd_pump = ( (meal_data.TDDPUMP / now ) * 24);
|
||||
}
|
||||
else {
|
||||
var tdd_pump = (( basal * 24 ) * 2.8);
|
||||
}
|
||||
console.log("Rolling TDD for last 24 hours is: "+tdd_24+"; ");
|
||||
|
||||
/*var tdd_pump_now = meal_data.TDDPUMP;
|
||||
var tdd_pump = ( tdd_pump_now / (now / 24));*/
|
||||
var TDD = (tdd7 * 0.4) + (tdd_pump * 0.6);
|
||||
|
||||
console.error("Pump extrapolated TDD = "+tdd_pump+"; ");
|
||||
//if (tdd7 > 0){
|
||||
if ( tdd_pump > tdd7 && now < 5 || now < 7 && TDD < ( 0.8 * tdd7 ) ){
|
||||
TDD = ( 0.8 * tdd7 );
|
||||
console.log("Excess or too low insulin from pump so TDD set to "+TDD+" based on 75% of TDD7; ");
|
||||
rT.reason += "TDD: " +TDD+ " due to low or high tdd from pump; ";
|
||||
}
|
||||
|
||||
else if (tdd_pump > (1.75 * tdd7)){
|
||||
TDD = tdd7;
|
||||
console.error("TDD set to TDD7 due to high pump usage reported. TDD = "+TDD+"; ");
|
||||
rT.reason += "TDD set to TDD7 due to high pump usage reported. TDD = "+TDD+"; ";
|
||||
}
|
||||
|
||||
|
||||
else if (tdd_pump < (0.33 * tdd7)){
|
||||
TDD = (tdd7 * 0.25) + (tdd_pump * 0.75);
|
||||
console.error("TDD weighted to pump due to low insulin usage. TDD = "+TDD+"; ");
|
||||
rT.reason += "TDD weighted to pump due to low insulin usage. TDD = "+TDD+"; ";
|
||||
}
|
||||
|
||||
else {
|
||||
console.log("TDD = " +TDD+ " based on standard pump 60/tdd7 40 split; ");
|
||||
rT.reason += "TDD: " +TDD+ " based on standard pump 60/tdd7 40 split; ";
|
||||
}
|
||||
|
||||
var dynISFadjust = profile.DynISFAdjust;
|
||||
var dynISFadjust = ( dynISFadjust / 100 );
|
||||
var TDD = (dynISFadjust * TDD);
|
||||
var variable_sens = (277700 / ( TDD * bg));
|
||||
variable_sens = round(variable_sens,1);
|
||||
if (dynISFadjust > 1 ) {
|
||||
console.log("TDD adjustment factor is: " +dynISFadjust+"; ");
|
||||
console.log("TDD adjusted to "+TDD+" using adjustment factor of "+dynISFadjust+"; ");
|
||||
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
|
||||
}
|
||||
else {
|
||||
var tdd_24 = (( basal * 24 ) * 2.8);
|
||||
else if (dynISFadjust < 1 ){
|
||||
console.log("TDD adjustment factor is: " +dynISFadjust+"; ");
|
||||
console.log("TDD adjusted to "+TDD+" using adjustment factor of "+dynISFadjust+"; ");
|
||||
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
|
||||
} else {
|
||||
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
|
||||
}
|
||||
sens = variable_sens;
|
||||
|
||||
//*********************************************************************************
|
||||
//** End of Dynamic ISF code for predictions **
|
||||
//*********************************************************************************
|
||||
|
||||
|
||||
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
|
||||
// w/ target 100, temp target 110 = .89, 120 = 0.8, 140 = 0.67, 160 = .57, and 200 = .44
|
||||
// e.g.: Sensitivity ratio set to 0.8 based on temp target of 120; Adjusting basal from 1.65 to 1.35; ISF from 58.9 to 73.6
|
||||
//sensitivityRatio = 2/(2+(target_bg-normalTarget)/40);
|
||||
var c = halfBasalTarget - normalTarget;
|
||||
sensitivityRatio = c/(c+target_bg-normalTarget);
|
||||
// limit sensitivityRatio to profile.autosens_max (1.2x by default)
|
||||
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
|
||||
sensitivityRatio = round(sensitivityRatio,2);
|
||||
console.log("Sensitivity ratio set to "+sensitivityRatio+" based on temp target of "+target_bg+"; ");
|
||||
sens = sens / sensitivityRatio ;
|
||||
sens = round(sens, 1);
|
||||
console.log("ISF from "+variable_sens+" to "+sens+ "due to temp target; ");
|
||||
}
|
||||
else {
|
||||
sensitivityRatio = ( tdd_24 / tdd7 );
|
||||
}
|
||||
if (sensitivityRatio > 1) {
|
||||
sensitivityRatio = Math.min(sensitivityRatio, profile.autosens_max);
|
||||
sensitivityRatio = round(sensitivityRatio,2);
|
||||
console.log("Sensitivity ratio: "+sensitivityRatio+"; ");
|
||||
}
|
||||
else if( sensitivityRatio < 1) {
|
||||
sensitivityRatio = Math.max(sensitivityRatio, profile.autosens_min);
|
||||
sensitivityRatio = round(sensitivityRatio,2);
|
||||
console.log("Sensitivity ratio: "+sensitivityRatio+"; ");
|
||||
}
|
||||
else {
|
||||
console.log("Sensitivity ratio: "+sensitivityRatio+"; ");
|
||||
}
|
||||
|
||||
|
||||
if (sensitivityRatio && profile.openapsama_useautosens === true) {
|
||||
basal = profile.current_basal * sensitivityRatio;
|
||||
basal = round_basal(basal, profile);
|
||||
if (basal !== profile_current_basal) {
|
||||
console.log("Adjusting basal from "+profile_current_basal+" to "+basal+"; ");
|
||||
} else {
|
||||
console.log("Autosens disabled. Basal unchanged: "+basal+"; ");
|
||||
}
|
||||
}
|
||||
|
||||
if (meal_data.TDDPUMP){
|
||||
var tdd_pump = ( (meal_data.TDDPUMP / now ) * 24);
|
||||
// adjust min, max, and target BG for sensitivity, such that 50% increase in ISF raises target from 100 to 120
|
||||
if (profile.temptargetSet) {
|
||||
//console.log("Temp Target set, not adjusting with autosens; ");
|
||||
} else {
|
||||
if ( profile.sensitivity_raises_target && sensitivityRatio < 1 && profile.openapsama_useautosens === true || profile.resistance_lowers_target && sensitivityRatio > 1 && profile.openapsama_useautosens === true) {
|
||||
// with a target of 100, default 0.7-1.2 autosens min/max range would allow a 93-117 target range
|
||||
min_bg = round((min_bg - 60) / sensitivityRatio) + 60;
|
||||
max_bg = round((max_bg - 60) / sensitivityRatio) + 60;
|
||||
var new_target_bg = round((target_bg - 60) / sensitivityRatio) + 60;
|
||||
// don't allow target_bg below 80
|
||||
new_target_bg = Math.max(80, new_target_bg);
|
||||
if (target_bg === new_target_bg) {
|
||||
console.log("target_bg unchanged: "+new_target_bg+"; ");
|
||||
} else {
|
||||
console.log("target_bg from "+target_bg+" to "+new_target_bg+"; ");
|
||||
}
|
||||
target_bg = new_target_bg;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var tdd_pump = (( basal * 24 ) * 2.8);
|
||||
|
||||
|
||||
if (typeof iob_data === 'undefined' ) {
|
||||
rT.error ='Error: iob_data undefined. ';
|
||||
return rT;
|
||||
}
|
||||
var TDD = (tdd7 * 0.4) + (tdd_pump * 0.6);
|
||||
|
||||
console.error("Pump extrapolated TDD = "+tdd_pump+"; ");
|
||||
//if (tdd7 > 0){
|
||||
if ( tdd_pump > tdd7 && now < 5 || now < 7 && TDD < ( 0.8 * tdd7 ) ){
|
||||
TDD = ( 0.8 * tdd7 );
|
||||
console.log("Excess or too low insulin from pump so TDD set to "+TDD+" based on 75% of TDD7; ");
|
||||
rT.reason += "TDD: " +TDD+ " due to low or high tdd from pump; ";
|
||||
}
|
||||
var iobArray = iob_data;
|
||||
if (typeof(iob_data.length) && iob_data.length > 1) {
|
||||
iob_data = iobArray[0];
|
||||
//console.error(JSON.stringify(iob_data[0]));
|
||||
}
|
||||
|
||||
else if (tdd_pump > (1.75 * tdd7)){
|
||||
TDD = tdd7;
|
||||
console.error("TDD set to TDD7 due to high pump usage reported. TDD = "+TDD+"; ");
|
||||
rT.reason += "TDD set to TDD7 due to high pump usage reported. TDD = "+TDD+"; ";
|
||||
}
|
||||
if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' ) {
|
||||
rT.error ='Error: iob_data missing some property. ';
|
||||
return rT;
|
||||
}
|
||||
|
||||
var tick;
|
||||
|
||||
else if (tdd_pump < (0.33 * tdd7)){
|
||||
TDD = (tdd7 * 0.25) + (tdd_pump * 0.75);
|
||||
console.error("TDD weighted to pump due to low insulin usage. TDD = "+TDD+"; ");
|
||||
rT.reason += "TDD weighted to pump due to low insulin usage. TDD = "+TDD+"; ";
|
||||
}
|
||||
if (glucose_status.delta > -0.5) {
|
||||
tick = "+" + round(glucose_status.delta,0);
|
||||
} else {
|
||||
tick = round(glucose_status.delta,0);
|
||||
}
|
||||
//var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
var minDelta = Math.min(glucose_status.delta, glucose_status.short_avgdelta);
|
||||
var minAvgDelta = Math.min(glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
var maxDelta = Math.max(glucose_status.delta, glucose_status.short_avgdelta, glucose_status.long_avgdelta);
|
||||
|
||||
else {
|
||||
console.log("TDD = " +TDD+ " based on standard pump 60/tdd7 40 split; ");
|
||||
rT.reason += "TDD: " +TDD+ " based on standard pump 60/tdd7 40 split; ";
|
||||
}
|
||||
|
||||
console.error(" ");
|
||||
|
||||
|
||||
var variable_sens = (277700 / (TDD * bg));
|
||||
variable_sens = round(variable_sens,1);
|
||||
console.log("Current sensitivity for predictions is " +variable_sens+" based on current bg");
|
||||
console.error(" ");
|
||||
|
||||
sens = variable_sens;
|
||||
if ( high_temptarget_raises_sensitivity && profile.temptargetSet && target_bg > normalTarget || profile.low_temptarget_lowers_sensitivity && profile.temptargetSet && target_bg < normalTarget ) {
|
||||
sens = sens / sensitivityRatio ;
|
||||
sens = round(sens, 1);
|
||||
console.log("ISF from "+variable_sens+" to "+sens+ "due to temp target; ");
|
||||
} else {
|
||||
sens = sens;
|
||||
sens = round(sens, 1);
|
||||
}
|
||||
|
||||
console.error("; CR:",profile.carb_ratio);
|
||||
|
||||
|
@ -772,19 +805,27 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_
|
|||
|
||||
console.error("UAM Impact:",uci,"mg/dL per 5m; UAM Duration:",UAMduration,"hours");
|
||||
|
||||
console.log("EventualBG is" +eventualBG+" ;");
|
||||
console.log("EventualBG is" +eventualBG+" ;");
|
||||
|
||||
if (bg > target_bg && glucose_status.delta < 3 && glucose_status.delta > -3 && glucose_status.short_avgdelta > -3 && glucose_status.short_avgdelta < 3 && eventualBG > target_bg && eventualBG < bg ) {
|
||||
var future_sens = ( 277700 / (TDD * ((eventualBG * 0.5) + (bg * 0.5) ) ) );
|
||||
console.log("Future state sensitivity is " +future_sens+" based on eventual and current bg due to flat glucose level above target");
|
||||
rT.reason += "Dosing sensitivity: " +future_sens+" using eventual BG;";
|
||||
}
|
||||
|
||||
else if( glucose_status.delta > 0 && eventualBG > target_bg ) {
|
||||
var future_sens = ( 277700 / (TDD * bg) );
|
||||
console.log("Future state sensitivity is " +future_sens+" using current bg due to small delta or variation");
|
||||
rT.reason += "Dosing sensitivity: " +future_sens+" using current BG;";
|
||||
}
|
||||
|
||||
else {
|
||||
var future_sens = ( 277700 / (TDD * eventualBG) );
|
||||
console.log("Future state sensitivity is " +future_sens+" based on eventual bg due to -ve delta");
|
||||
rT.reason += "Dosing sensitivity: " +future_sens+" using eventual BG;";
|
||||
}
|
||||
var future_sens = round(future_sens,1);
|
||||
|
||||
if( glucose_status.delta >= 0 || bg > 60 && glucose_status.delta < 2 && glucose_status.delta > -2 && glucose_status.short_avgdelta > -2 && glucose_status.short_avgdelta < 2 || eventualBG > target_bg && glucose_status.delta < 0 ) {
|
||||
var future_sens = ( 277700 / (TDD * bg) );
|
||||
console.log("Future state sensitivity is " +future_sens+" using current bg due to no COB & small delta or variation");
|
||||
rT.reason += "Dosing sensitivity: " +future_sens+" using current BG;";
|
||||
}
|
||||
else {
|
||||
var future_sens = ( 277700 / (TDD * eventualBG));
|
||||
console.log("Future state sensitivity is " +future_sens+" based on eventual bg due to -ve delta");
|
||||
rT.reason += "Dosing sensitivity: " +future_sens+" using eventual BG;";
|
||||
}
|
||||
var future_sens = round(future_sens,1);
|
||||
|
||||
|
||||
minIOBPredBG = Math.max(39,minIOBPredBG);
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.os.Bundle
|
|||
import android.os.PersistableBundle
|
||||
import android.text.SpannableString
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.util.Linkify
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
|
@ -19,10 +20,10 @@ import android.widget.EditText
|
|||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.joanzapata.iconify.Iconify
|
||||
|
@ -33,6 +34,7 @@ import info.nightscout.androidaps.database.entities.UserEntry.Action
|
|||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.databinding.ActivityMainBinding
|
||||
import info.nightscout.androidaps.events.EventAppExit
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
|
@ -50,6 +52,7 @@ import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
|||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.extensions.isRunningRealPumpTest
|
||||
import info.nightscout.androidaps.utils.locale.LocaleHelper
|
||||
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.tabs.TabPageAdapter
|
||||
|
@ -67,7 +70,6 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
private val disposable = CompositeDisposable()
|
||||
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var androidPermission: AndroidPermission
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var versionCheckerUtils: VersionCheckerUtils
|
||||
|
@ -84,12 +86,13 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var passwordCheck: PasswordCheck
|
||||
|
||||
private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
|
||||
private var pluginPreferencesMenuItem: MenuItem? = null
|
||||
private var menu: Menu? = null
|
||||
private var menuOpen = false
|
||||
|
||||
private var isProtectionCheckActive = false
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -115,6 +118,7 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
override fun onPageSelected(position: Int) {
|
||||
setPluginPreferenceMenuName()
|
||||
checkPluginPreferences(binding.mainPager)
|
||||
setDisabledMenuItemColorPluginPreferences()
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -134,6 +138,12 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ processPreferenceChange(it) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventInitializationChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({
|
||||
passwordCheck.passwordResetCheck(this)
|
||||
}, fabricPrivacy::logException)
|
||||
if (startWizard() && !isRunningRealPumpTest()) {
|
||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, {
|
||||
startActivity(Intent(this, SetupWizardActivity::class.java))
|
||||
|
@ -168,10 +178,13 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null,
|
||||
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { finish() } },
|
||||
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { finish() } }
|
||||
)
|
||||
if (!isProtectionCheckActive) {
|
||||
isProtectionCheckActive = true
|
||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, UIRunnable { isProtectionCheckActive = false },
|
||||
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { isProtectionCheckActive = false; finish() } },
|
||||
UIRunnable { OKDialog.show(this, "", rh.gs(R.string.authorizationfailed)) { isProtectionCheckActive = false; finish() } }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setWakeLock() {
|
||||
|
@ -252,6 +265,14 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
return super.dispatchTouchEvent(event)
|
||||
}
|
||||
|
||||
private fun setDisabledMenuItemColorPluginPreferences() {
|
||||
if (pluginPreferencesMenuItem?.isEnabled == false) {
|
||||
val spanString = SpannableString(this.menu?.findItem(R.id.nav_plugin_preferences)?.title.toString())
|
||||
spanString.setSpan(ForegroundColorSpan(rh.gac(R.attr.disabledTextColor)), 0, spanString.length, 0)
|
||||
this.menu?.findItem(R.id.nav_plugin_preferences)?.title = spanString
|
||||
}
|
||||
}
|
||||
|
||||
private fun setPluginPreferenceMenuName() {
|
||||
if (binding.mainPager.currentItem >= 0) {
|
||||
val plugin = (binding.mainPager.adapter as TabPageAdapter).getPluginAt(binding.mainPager.currentItem)
|
||||
|
@ -270,7 +291,7 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
|
||||
override fun onPanelClosed(featureId: Int, menu: Menu) {
|
||||
menuOpen = false;
|
||||
menuOpen = false
|
||||
super.onPanelClosed(featureId, menu)
|
||||
}
|
||||
|
||||
|
@ -280,6 +301,7 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences)
|
||||
setPluginPreferenceMenuName()
|
||||
checkPluginPreferences(binding.mainPager)
|
||||
setDisabledMenuItemColorPluginPreferences()
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -320,7 +342,7 @@ class MainActivity : NoSplashAppCompatActivity() {
|
|||
message += rh.gs(R.string.about_link_urls)
|
||||
val messageSpanned = SpannableString(message)
|
||||
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS)
|
||||
AlertDialog.Builder(this, R.style.DialogTheme)
|
||||
MaterialAlertDialogBuilder(this, R.style.DialogTheme)
|
||||
.setTitle(rh.gs(R.string.app_name) + " " + BuildConfig.VERSION)
|
||||
.setIcon(iconsProvider.getIcon())
|
||||
.setMessage(messageSpanned)
|
||||
|
|
|
@ -6,6 +6,13 @@ import android.content.IntentFilter
|
|||
import android.net.ConnectivityManager
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import com.uber.rxdogtag.RxDogTag
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.DaggerApplication
|
||||
|
@ -20,24 +27,23 @@ import info.nightscout.androidaps.di.StaticInjector
|
|||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.ConfigBuilder
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
|
||||
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||
import info.nightscout.androidaps.receivers.BTReceiver
|
||||
import info.nightscout.androidaps.receivers.ChargingStateReceiver
|
||||
import info.nightscout.androidaps.receivers.KeepAliveReceiver.KeepAliveManager
|
||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
||||
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver
|
||||
import info.nightscout.androidaps.plugins.general.themes.ThemeSwitcherPlugin
|
||||
import info.nightscout.androidaps.receivers.*
|
||||
import info.nightscout.androidaps.services.AlarmSoundServiceHelper
|
||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.LocalAlertUtils
|
||||
import info.nightscout.androidaps.utils.ProcessLifecycleListener
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.locale.LocaleHelper
|
||||
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||
import info.nightscout.androidaps.widget.updateWidget
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.exceptions.UndeliverableException
|
||||
|
@ -46,6 +52,7 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins
|
|||
import net.danlew.android.joda.JodaTimeAndroid
|
||||
import java.io.IOException
|
||||
import java.net.SocketException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class MainApp : DaggerApplication() {
|
||||
|
@ -60,16 +67,20 @@ class MainApp : DaggerApplication() {
|
|||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var buildHelper: BuildHelper
|
||||
@Inject lateinit var configBuilder: ConfigBuilder
|
||||
@Inject lateinit var keepAliveManager: KeepAliveManager
|
||||
@Inject lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
|
||||
@Inject lateinit var compatDBHelper: CompatDBHelper
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var passwordCheck: PasswordCheck
|
||||
@Inject lateinit var alarmSoundServiceHelper: AlarmSoundServiceHelper
|
||||
@Inject lateinit var notificationStore: NotificationStore
|
||||
@Inject lateinit var processLifecycleListener: ProcessLifecycleListener
|
||||
@Inject lateinit var profileSwitchPlugin: ThemeSwitcherPlugin
|
||||
@Inject lateinit var localAlertUtils: LocalAlertUtils
|
||||
|
||||
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
private lateinit var refreshWidget: Runnable
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
@ -77,6 +88,7 @@ class MainApp : DaggerApplication() {
|
|||
RxDogTag.install()
|
||||
setRxErrorHandler()
|
||||
LocaleHelper.update(this)
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(processLifecycleListener)
|
||||
|
||||
var gitRemote: String? = BuildConfig.REMOTE
|
||||
var commitHash: String? = BuildConfig.HEAD
|
||||
|
@ -84,21 +96,10 @@ class MainApp : DaggerApplication() {
|
|||
gitRemote = null
|
||||
commitHash = null
|
||||
}
|
||||
disposable += repository.runTransaction(VersionChangeTransaction(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, gitRemote, commitHash)).subscribe()
|
||||
if (sp.getBoolean(R.string.key_ns_logappstartedevent, config.APS))
|
||||
disposable += repository
|
||||
.runTransaction(
|
||||
InsertIfNewByTimestampTherapyEventTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
type = TherapyEvent.Type.NOTE,
|
||||
note = getString(info.nightscout.androidaps.core.R.string.androidaps_start) + " - " + Build.MANUFACTURER + " " + Build.MODEL,
|
||||
glucoseUnit = TherapyEvent.GlucoseUnit.MGDL
|
||||
)
|
||||
)
|
||||
.subscribe()
|
||||
disposable += compatDBHelper.dbChangeDisposable()
|
||||
registerActivityLifecycleCallbacks(activityMonitor)
|
||||
JodaTimeAndroid.init(this)
|
||||
profileSwitchPlugin.setThemeMode()
|
||||
aapsLogger.debug("Version: " + BuildConfig.VERSION_NAME)
|
||||
aapsLogger.debug("BuildVersion: " + BuildConfig.BUILDVERSION)
|
||||
aapsLogger.debug("Remote: " + BuildConfig.REMOTE)
|
||||
|
@ -113,10 +114,38 @@ class MainApp : DaggerApplication() {
|
|||
// Register all tabs in app here
|
||||
pluginStore.plugins = plugins
|
||||
configBuilder.initialize()
|
||||
keepAliveManager.setAlarm(this)
|
||||
|
||||
disposable += repository.runTransaction(VersionChangeTransaction(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, gitRemote, commitHash)).subscribe()
|
||||
if (sp.getBoolean(R.string.key_ns_logappstartedevent, config.APS))
|
||||
disposable += repository
|
||||
.runTransaction(
|
||||
InsertIfNewByTimestampTherapyEventTransaction(
|
||||
timestamp = dateUtil.now(),
|
||||
type = TherapyEvent.Type.NOTE,
|
||||
note = getString(info.nightscout.androidaps.core.R.string.androidaps_start) + " - " + Build.MANUFACTURER + " " + Build.MODEL,
|
||||
glucoseUnit = TherapyEvent.GlucoseUnit.MGDL
|
||||
)
|
||||
)
|
||||
.subscribe()
|
||||
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
||||
"KeepAlive",
|
||||
ExistingPeriodicWorkPolicy.REPLACE,
|
||||
PeriodicWorkRequest.Builder(KeepAliveWorker::class.java, 15, TimeUnit.MINUTES)
|
||||
.setInputData(Data.Builder().putString("schedule", "KeepAlive").build())
|
||||
.setInitialDelay(5, TimeUnit.SECONDS)
|
||||
.build()
|
||||
)
|
||||
localAlertUtils.shortenSnoozeInterval()
|
||||
localAlertUtils.preSnoozeAlarms()
|
||||
doMigrations()
|
||||
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
|
||||
passwordCheck.passwordResetCheck(this)
|
||||
|
||||
// schedule widget update
|
||||
refreshWidget = Runnable {
|
||||
handler.postDelayed(refreshWidget, 60000)
|
||||
updateWidget(this)
|
||||
}
|
||||
handler.postDelayed(refreshWidget, 60000)
|
||||
}
|
||||
|
||||
private fun setRxErrorHandler() {
|
||||
|
@ -186,7 +215,6 @@ class MainApp : DaggerApplication() {
|
|||
override fun onTerminate() {
|
||||
aapsLogger.debug(LTag.CORE, "onTerminate")
|
||||
unregisterActivityLifecycleCallbacks(activityMonitor)
|
||||
keepAliveManager.cancelAlarm(this)
|
||||
alarmSoundServiceHelper.stopService(this)
|
||||
super.onTerminate()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package info.nightscout.androidaps.activities
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.DatePickerDialog
|
||||
import android.graphics.Color
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.ViewGroup
|
||||
|
@ -18,21 +18,19 @@ import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
|||
import info.nightscout.androidaps.events.EventCustomCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.extensions.toVisibilityKeepSpace
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
||||
import info.nightscout.androidaps.plugins.general.overview.OverviewMenus
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewGraph
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
|
@ -40,6 +38,7 @@ import info.nightscout.androidaps.utils.T
|
|||
import info.nightscout.androidaps.utils.Translator
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.workflow.CalculationWorkflow
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
|
@ -52,15 +51,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
@Inject lateinit var injector: HasAndroidInjector
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var buildHelper: BuildHelper
|
||||
@Inject lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin
|
||||
@Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin
|
||||
@Inject lateinit var sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var overviewMenus: OverviewMenus
|
||||
|
@ -69,6 +64,9 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
@Inject lateinit var loop: Loop
|
||||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||
@Inject lateinit var translator: Translator
|
||||
@Inject lateinit var context: Context
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
@Inject lateinit var calculationWorkflow: CalculationWorkflow
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
|
@ -91,6 +89,17 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
setContentView(binding.root)
|
||||
|
||||
// We don't want to use injected singletons but own instance working on top of different data
|
||||
overviewData =
|
||||
OverviewData(
|
||||
aapsLogger,
|
||||
rh,
|
||||
dateUtil,
|
||||
sp,
|
||||
activePlugin,
|
||||
defaultValueHelper,
|
||||
profileFunction,
|
||||
repository
|
||||
)
|
||||
iobCobCalculator =
|
||||
IobCobCalculatorPlugin(
|
||||
injector,
|
||||
|
@ -101,30 +110,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
rh,
|
||||
profileFunction,
|
||||
activePlugin,
|
||||
sensitivityOref1Plugin,
|
||||
sensitivityAAPSPlugin,
|
||||
sensitivityWeightedAveragePlugin,
|
||||
fabricPrivacy,
|
||||
dateUtil,
|
||||
repository
|
||||
)
|
||||
overviewData =
|
||||
OverviewData(
|
||||
injector,
|
||||
aapsLogger,
|
||||
rh,
|
||||
dateUtil,
|
||||
sp,
|
||||
activePlugin,
|
||||
defaultValueHelper,
|
||||
profileFunction,
|
||||
config,
|
||||
loop,
|
||||
nsDeviceStatus,
|
||||
repository,
|
||||
overviewMenus,
|
||||
iobCobCalculator,
|
||||
translator
|
||||
overviewData,
|
||||
calculationWorkflow
|
||||
)
|
||||
|
||||
binding.left.setOnClickListener {
|
||||
|
@ -179,7 +169,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
val cal = Calendar.getInstance()
|
||||
cal.timeInMillis = overviewData.fromTime
|
||||
DatePickerDialog(
|
||||
this, R.style.MaterialPickerTheme,
|
||||
this,
|
||||
dateSetListener,
|
||||
cal.get(Calendar.YEAR),
|
||||
cal.get(Calendar.MONTH),
|
||||
|
@ -188,18 +178,19 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
|
||||
val dm = DisplayMetrics()
|
||||
@Suppress("DEPRECATION")
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
|
||||
display?.getRealMetrics(dm)
|
||||
else
|
||||
@Suppress("DEPRECATION") windowManager.defaultDisplay.getMetrics(dm)
|
||||
windowManager.defaultDisplay.getMetrics(dm)
|
||||
|
||||
|
||||
axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
|
||||
binding.bgGraph.gridLabelRenderer?.gridColor = rh.gc(R.color.graphgrid)
|
||||
binding.bgGraph.gridLabelRenderer?.gridColor = rh.gac(this, R.attr.graphgrid)
|
||||
binding.bgGraph.gridLabelRenderer?.reloadStyles()
|
||||
binding.bgGraph.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||
|
||||
overviewMenus.setupChartMenu(binding.chartMenuButton)
|
||||
overviewMenus.setupChartMenu(context, binding.chartMenuButton)
|
||||
prepareGraphsIfNeeded(overviewMenus.setting.size)
|
||||
savedInstanceState?.let { bundle ->
|
||||
rangeToDisplay = bundle.getInt("rangeToDisplay", 0)
|
||||
|
@ -211,7 +202,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposable.clear()
|
||||
iobCobCalculator.stopCalculation("onPause")
|
||||
calculationWorkflow.stopCalculation(CalculationWorkflow.HISTORY_CALCULATION, "onPause")
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -233,22 +224,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
disposable += rxBus
|
||||
.toObservable(EventIobCalculationProgress::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({
|
||||
if (it.cause is EventCustomCalculationFinished)
|
||||
binding.overviewIobcalculationprogess.text = it.progress
|
||||
}, fabricPrivacy::logException)
|
||||
.subscribe({ updateCalcProgress(it.pass.finalPercent(it.progressPct)) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventRefreshOverview::class.java)
|
||||
.toObservable(EventUpdateOverviewGraph::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGUI("EventRefreshOverview") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventBucketedDataCreated::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
overviewData.prepareBucketedData("EventBucketedDataCreated")
|
||||
overviewData.prepareBgData("EventBucketedDataCreated")
|
||||
rxBus.send(EventRefreshOverview("EventBucketedDataCreated"))
|
||||
}, fabricPrivacy::logException)
|
||||
|
||||
if (overviewData.fromTime == 0L) {
|
||||
// set start of current day
|
||||
|
@ -279,12 +259,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
val graph = GraphView(this)
|
||||
graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, rh.dpToPx(100)).also { it.setMargins(0, rh.dpToPx(15), 0, rh.dpToPx(10)) }
|
||||
graph.gridLabelRenderer?.gridColor = rh.gc(R.color.graphgrid)
|
||||
graph.gridLabelRenderer?.gridColor = rh.gac(R.attr.graphgrid)
|
||||
graph.gridLabelRenderer?.reloadStyles()
|
||||
graph.gridLabelRenderer?.isHorizontalLabelsVisible = false
|
||||
graph.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||
graph.gridLabelRenderer?.numVerticalLabels = 3
|
||||
graph.viewport.backgroundColor = Color.argb(20, 255, 255, 255) // 8% of gray
|
||||
graph.viewport.backgroundColor = rh.gac(this, R.attr.viewPortbackgroundColor)
|
||||
relativeLayout.addView(graph)
|
||||
|
||||
val label = TextView(this)
|
||||
|
@ -304,17 +284,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
@Suppress("SameParameterValue")
|
||||
private fun loadAll(from: String) {
|
||||
updateDate()
|
||||
Thread {
|
||||
overviewData.prepareBgData("$from")
|
||||
overviewData.prepareTreatmentsData(from)
|
||||
rxBus.send(EventRefreshOverview("loadAll_$from"))
|
||||
overviewData.prepareTemporaryTargetData(from)
|
||||
rxBus.send(EventRefreshOverview("loadAll_$from"))
|
||||
overviewData.prepareBasalData(from)
|
||||
rxBus.send(EventRefreshOverview(from))
|
||||
aapsLogger.debug(LTag.UI, "loadAll $from finished")
|
||||
runCalculation(from)
|
||||
}.start()
|
||||
runCalculation(from)
|
||||
}
|
||||
|
||||
private fun setTime(start: Long) {
|
||||
|
@ -335,25 +305,32 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun runCalculation(from: String) {
|
||||
Thread {
|
||||
iobCobCalculator.stopCalculation(from)
|
||||
iobCobCalculator.stopCalculationTrigger = false
|
||||
iobCobCalculator.runCalculation(from, overviewData.toTime, bgDataReload = true, limitDataToOldestAvailable = false, cause = EventCustomCalculationFinished())
|
||||
}.start()
|
||||
calculationWorkflow.runCalculation(
|
||||
CalculationWorkflow.HISTORY_CALCULATION,
|
||||
iobCobCalculator,
|
||||
overviewData,
|
||||
from,
|
||||
overviewData.toTime,
|
||||
bgDataReload = true,
|
||||
limitDataToOldestAvailable = false,
|
||||
cause = EventCustomCalculationFinished(),
|
||||
runLoop = false
|
||||
)
|
||||
}
|
||||
|
||||
@Volatile
|
||||
var runningRefresh = false
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun refreshLoop(from: String) {
|
||||
if (runningRefresh) return
|
||||
runningRefresh = true
|
||||
overviewData.prepareIobAutosensData(from)
|
||||
rxBus.send(EventRefreshOverview(from))
|
||||
aapsLogger.debug(LTag.UI, "refreshLoop finished")
|
||||
runningRefresh = false
|
||||
}
|
||||
|
||||
fun updateDate() {
|
||||
private fun updateDate() {
|
||||
binding.date.text = dateUtil.dateAndTimeString(overviewData.fromTime)
|
||||
binding.zoom.text = rangeToDisplay.toString()
|
||||
}
|
||||
|
@ -372,6 +349,8 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
|
||||
if (buildHelper.isDev()) graphData.addBucketedData()
|
||||
graphData.addTreatments()
|
||||
if (menuChartSettings[0][OverviewMenus.CharType.TREAT.ordinal])
|
||||
graphData.addTherapyEvents()
|
||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
||||
graphData.addActivity(0.8)
|
||||
if (pump.pumpDescription.isTempBasalCapable && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
||||
|
@ -400,12 +379,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
var useDSForScale = false
|
||||
var useBGIForScale = false
|
||||
when {
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
|
||||
}
|
||||
val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
|
||||
|
@ -437,4 +416,9 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
|
|||
secondaryGraphsData[g].performUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCalcProgress(percent: Int) {
|
||||
binding.progressBar.progress = percent
|
||||
binding.progressBar.visibility = (percent != 100).toVisibilityKeepSpace()
|
||||
}
|
||||
}
|
|
@ -8,17 +8,17 @@ import android.os.Bundle
|
|||
import androidx.annotation.XmlRes
|
||||
import androidx.preference.*
|
||||
import dagger.android.support.AndroidSupportInjection
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
|
||||
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
||||
import info.nightscout.androidaps.danar.DanaRPlugin
|
||||
import info.nightscout.androidaps.danars.DanaRSPlugin
|
||||
import info.nightscout.androidaps.diaconn.DiaconnG8Plugin
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugin.general.openhumans.OpenHumansUploader
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
|
@ -44,11 +44,11 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
|||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
||||
import info.nightscout.androidaps.plugins.source.*
|
||||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
|
||||
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.*
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -236,7 +236,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
rh.gs(R.string.key_application_protection) == key ||
|
||||
rh.gs(R.string.key_bolus_protection) == key) &&
|
||||
sp.getString(R.string.key_master_password, "") == "" &&
|
||||
sp.getInt(key, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal
|
||||
sp.getInt(key, NONE.ordinal) == BIOMETRIC.ordinal
|
||||
) {
|
||||
activity?.let {
|
||||
val title = rh.gs(R.string.unsecure_fallback_biometric)
|
||||
|
@ -246,9 +246,9 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
}
|
||||
|
||||
// Master password erased with activated Biometric protection
|
||||
val isBiometricActivated = sp.getInt(R.string.key_settings_protection, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal ||
|
||||
sp.getInt(R.string.key_application_protection, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal ||
|
||||
sp.getInt(R.string.key_bolus_protection, ProtectionCheck.ProtectionType.NONE.ordinal) == ProtectionCheck.ProtectionType.BIOMETRIC.ordinal
|
||||
val isBiometricActivated = sp.getInt(R.string.key_settings_protection, NONE.ordinal) == BIOMETRIC.ordinal ||
|
||||
sp.getInt(R.string.key_application_protection, NONE.ordinal) == BIOMETRIC.ordinal ||
|
||||
sp.getInt(R.string.key_bolus_protection, NONE.ordinal) == BIOMETRIC.ordinal
|
||||
if (rh.gs(R.string.key_master_password) == key && sp.getString(key, "") == "" && isBiometricActivated) {
|
||||
activity?.let {
|
||||
val title = rh.gs(R.string.unsecure_fallback_biometric)
|
||||
|
@ -319,26 +319,35 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
if (pref is ListPreference) {
|
||||
pref.setSummary(pref.entry)
|
||||
// Preferences
|
||||
// Preferences
|
||||
if (pref.getKey() == rh.gs(R.string.key_settings_protection)) {
|
||||
val pass: Preference? = findPreference(rh.gs(R.string.key_settings_password))
|
||||
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
|
||||
val usePassword = pref.value == CUSTOM_PASSWORD.ordinal.toString()
|
||||
pass?.let { it.isVisible = usePassword }
|
||||
val pin: Preference? = findPreference(rh.gs(R.string.key_settings_pin))
|
||||
val usePin = pref.value == CUSTOM_PIN.ordinal.toString()
|
||||
pin?.let { it.isVisible = usePin }
|
||||
}
|
||||
// Application
|
||||
// Application
|
||||
if (pref.getKey() == rh.gs(R.string.key_application_protection)) {
|
||||
val pass: Preference? = findPreference(rh.gs(R.string.key_application_password))
|
||||
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
|
||||
val usePassword = pref.value == CUSTOM_PASSWORD.ordinal.toString()
|
||||
pass?.let { it.isVisible = usePassword }
|
||||
val pin: Preference? = findPreference(rh.gs(R.string.key_application_pin))
|
||||
val usePin = pref.value == CUSTOM_PIN.ordinal.toString()
|
||||
pin?.let { it.isVisible = usePin }
|
||||
}
|
||||
// Bolus
|
||||
// Bolus
|
||||
if (pref.getKey() == rh.gs(R.string.key_bolus_protection)) {
|
||||
val pass: Preference? = findPreference(rh.gs(R.string.key_bolus_password))
|
||||
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
|
||||
val usePassword = pref.value == CUSTOM_PASSWORD.ordinal.toString()
|
||||
pass?.let { it.isVisible = usePassword }
|
||||
val pin: Preference? = findPreference(rh.gs(R.string.key_bolus_pin))
|
||||
val usePin = pref.value == CUSTOM_PIN.ordinal.toString()
|
||||
pin?.let { it.isVisible = usePin }
|
||||
}
|
||||
}
|
||||
if (pref is EditTextPreference) {
|
||||
if (pref.getKey().contains("password") || pref.getKey().contains("secret")) {
|
||||
if (pref.getKey().contains("password") || pref.getKey().contains("pin") || pref.getKey().contains("secret")) {
|
||||
pref.setSummary("******")
|
||||
} else if (pref.text != null) {
|
||||
pref.dialogMessage = pref.dialogMessage
|
||||
|
@ -354,7 +363,10 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
rh.gs(R.string.key_bolus_password),
|
||||
rh.gs(R.string.key_master_password),
|
||||
rh.gs(R.string.key_application_password),
|
||||
rh.gs(R.string.key_settings_password)
|
||||
rh.gs(R.string.key_settings_password),
|
||||
rh.gs(R.string.key_bolus_pin),
|
||||
rh.gs(R.string.key_application_pin),
|
||||
rh.gs(R.string.key_settings_pin)
|
||||
)
|
||||
|
||||
if (pref is Preference) {
|
||||
|
@ -362,7 +374,11 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
if (sp.getString(pref.key, "").startsWith("hmac:")) {
|
||||
pref.summary = "******"
|
||||
} else {
|
||||
pref.summary = rh.gs(R.string.password_not_set)
|
||||
if (pref.key.contains("pin")) {
|
||||
pref.summary = rh.gs(R.string.pin_not_set)
|
||||
}else {
|
||||
pref.summary = rh.gs(R.string.password_not_set)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,6 +424,18 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
passwordCheck.setPassword(context, R.string.application_password, R.string.key_application_password)
|
||||
return true
|
||||
}
|
||||
if (preference.key == rh.gs(R.string.key_settings_pin)) {
|
||||
passwordCheck.setPassword(context, R.string.settings_pin, R.string.key_settings_pin, pinInput = true)
|
||||
return true
|
||||
}
|
||||
if (preference.key == rh.gs(R.string.key_bolus_pin)) {
|
||||
passwordCheck.setPassword(context, R.string.bolus_pin, R.string.key_bolus_pin, pinInput = true)
|
||||
return true
|
||||
}
|
||||
if (preference.key == rh.gs(R.string.key_application_pin)) {
|
||||
passwordCheck.setPassword(context, R.string.application_pin, R.string.key_application_pin, pinInput = true)
|
||||
return true
|
||||
}
|
||||
// NSClient copy settings
|
||||
if (preference.key == rh.gs(R.string.key_statuslights_copy_ns)) {
|
||||
nsSettingStatus.copyStatusLightsNsSettings(context)
|
||||
|
@ -421,4 +449,4 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
this.filter = filter
|
||||
preferenceManager?.preferenceScreen?.let { updateFilterVisibility(filter, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.MenuItem
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceScreen
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -19,6 +20,7 @@ class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompa
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setTheme(R.style.AppTheme)
|
||||
binding = ActivityPreferencesBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
@ -61,4 +63,14 @@ class PreferencesActivity : NoSplashAppCompatActivity(), PreferenceFragmentCompa
|
|||
private fun filterPreferences() {
|
||||
myPreferenceFragment?.setFilter(binding.prefFilter.text.toString())
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import android.text.Editable
|
|||
import android.text.TextWatcher
|
||||
import android.view.Menu
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.TextView
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.ProfileSealed
|
||||
import info.nightscout.androidaps.data.PureProfile
|
||||
|
@ -37,7 +38,6 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
@Inject lateinit var defaultProfile: DefaultProfile
|
||||
@Inject lateinit var defaultProfileDPV: DefaultProfileDPV
|
||||
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var repository: AppRepository
|
||||
|
@ -66,9 +66,9 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
private lateinit var binding: ActivityProfilehelperBinding
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityProfilehelperBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
@ -79,11 +79,11 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
switchTab(1, typeSelected[1])
|
||||
}
|
||||
|
||||
binding.profiletype.setOnClickListener {
|
||||
PopupMenu(this, binding.profiletype).apply {
|
||||
binding.profileType.setOnClickListener {
|
||||
PopupMenu(this, binding.profileType).apply {
|
||||
menuInflater.inflate(R.menu.menu_profilehelper, menu)
|
||||
setOnMenuItemClickListener { item ->
|
||||
binding.profiletype.setText(item.title)
|
||||
binding.profileType.setText(item.title)
|
||||
when (item.itemId) {
|
||||
R.id.menu_default -> switchTab(tabSelected, ProfileType.MOTOL_DEFAULT)
|
||||
R.id.menu_default_dpv -> switchTab(tabSelected, ProfileType.DPV_DEFAULT)
|
||||
|
@ -130,7 +130,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
|
||||
// Default profile
|
||||
binding.copytolocalprofile.setOnClickListener {
|
||||
binding.copyToLocalProfile.setOnClickListener {
|
||||
storeValues()
|
||||
val age = ageUsed[tabSelected]
|
||||
val weight = weightUsed[tabSelected]
|
||||
|
@ -168,20 +168,22 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
})
|
||||
|
||||
binding.basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null)
|
||||
binding.basalPctFromTdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null)
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress)
|
||||
binding.tdds.addView(TextView(this).apply { text = rh.gs(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) })
|
||||
Thread {
|
||||
val tdds = tddCalculator.stats()
|
||||
runOnUiThread { binding.tdds.text = tdds }
|
||||
val tdds = tddCalculator.stats(this)
|
||||
runOnUiThread {
|
||||
binding.tdds.removeAllViews()
|
||||
binding.tdds.addView(tdds)
|
||||
}
|
||||
}.start()
|
||||
|
||||
// Current profile
|
||||
binding.currentProfileText.text = profileFunction.getProfileName()
|
||||
|
||||
// General
|
||||
binding.compareprofile.setOnClickListener {
|
||||
binding.compareProfiles.setOnClickListener {
|
||||
storeValues()
|
||||
for (i in 0..1) {
|
||||
if (typeSelected[i] == ProfileType.MOTOL_DEFAULT) {
|
||||
|
@ -239,10 +241,10 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
ToastUtils.showToastInUiThread(this, R.string.invalidinput)
|
||||
}
|
||||
binding.age.editText?.id?.let { binding.ageLabel.labelFor = it }
|
||||
binding.tdd.editText?.id?.let { binding.tddLabel.labelFor = it }
|
||||
binding.weight.editText?.id?.let { binding.weightLabel.labelFor = it }
|
||||
binding.basalpctfromtdd.editText?.id?.let { binding.basalpctfromtddLabel.labelFor = it }
|
||||
binding.ageLabel.labelFor = binding.age.editTextId
|
||||
binding.tddLabel.labelFor = binding.tdd.editTextId
|
||||
binding.weightLabel.labelFor = binding.weight.editTextId
|
||||
binding.basalPctFromTddLabel.labelFor = binding.basalPctFromTdd.editTextId
|
||||
|
||||
switchTab(0, typeSelected[0], false)
|
||||
}
|
||||
|
@ -273,7 +275,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
ageUsed[tabSelected] = binding.age.value
|
||||
weightUsed[tabSelected] = binding.weight.value
|
||||
tddUsed[tabSelected] = binding.tdd.value
|
||||
pctUsed[tabSelected] = binding.basalpctfromtdd.value
|
||||
pctUsed[tabSelected] = binding.basalPctFromTdd.value
|
||||
}
|
||||
|
||||
private fun switchTab(tab: Int, newContent: ProfileType, storeOld: Boolean = true) {
|
||||
|
@ -283,10 +285,10 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
tabSelected = tab
|
||||
typeSelected[tabSelected] = newContent
|
||||
binding.profiletypeTitle.defaultHintTextColor = ColorStateList.valueOf(rh.gc(if (tab == 0) R.color.helperProfile else R.color.examinedProfile))
|
||||
binding.profileTypeTitle.defaultHintTextColor = ColorStateList.valueOf(rh.gac( this, if (tab == 0) R.attr.helperProfileColor else R.attr.examinedProfileColor))
|
||||
|
||||
// show new content
|
||||
binding.profiletype.setText(
|
||||
binding.profileType.setText(
|
||||
when (typeSelected[tabSelected]) {
|
||||
ProfileType.MOTOL_DEFAULT -> rh.gs(R.string.motoldefaultprofile)
|
||||
ProfileType.DPV_DEFAULT -> rh.gs(R.string.dpvdefaultprofile)
|
||||
|
@ -304,9 +306,9 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
binding.age.value = ageUsed[tabSelected]
|
||||
binding.weight.value = weightUsed[tabSelected]
|
||||
binding.tdd.value = tddUsed[tabSelected]
|
||||
binding.basalpctfromtdd.value = pctUsed[tabSelected]
|
||||
binding.basalPctFromTdd.value = pctUsed[tabSelected]
|
||||
|
||||
binding.basalpctfromtddRow.visibility = (newContent == ProfileType.DPV_DEFAULT).toVisibility()
|
||||
binding.basalPctFromTddRow.visibility = (newContent == ProfileType.DPV_DEFAULT).toVisibility()
|
||||
if (profileList.isNotEmpty())
|
||||
binding.availableProfileList.setText(profileList[profileUsed[tabSelected]].toString())
|
||||
if (profileSwitch.isNotEmpty())
|
||||
|
@ -314,7 +316,7 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
}
|
||||
|
||||
private fun setBackgroundColorOnSelected(tab: Int) {
|
||||
binding.menu1.setBackgroundColor(rh.gc(if (tab == 1) R.color.defaultbackground else R.color.helperProfile))
|
||||
binding.menu2.setBackgroundColor(rh.gc(if (tab == 0) R.color.defaultbackground else R.color.examinedProfile))
|
||||
binding.menu1.setBackgroundColor(rh.gac(this, if (tab == 1) R.attr.defaultbackground else R.attr.helperProfileColor))
|
||||
binding.menu2.setBackgroundColor(rh.gac(this, if (tab == 0) R.attr.defaultbackground else R.attr.examinedProfileColor))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.activities
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.widget.TextView
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
|
@ -9,7 +10,6 @@ import info.nightscout.androidaps.databinding.ActivityStatsBinding
|
|||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.stats.TddCalculator
|
||||
import info.nightscout.androidaps.utils.stats.TirCalculator
|
||||
import javax.inject.Inject
|
||||
|
@ -29,21 +29,30 @@ class StatsActivity : NoSplashAppCompatActivity() {
|
|||
binding = ActivityStatsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress)
|
||||
binding.tir.text = getString(R.string.tir) + ": " + rh.gs(R.string.calculation_in_progress)
|
||||
binding.activity.text = rh.gs(R.string.activitymonitor) + ": " + rh.gs(R.string.calculation_in_progress)
|
||||
binding.tdds.addView(TextView(this).apply { text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) })
|
||||
binding.tir.addView(TextView(this).apply { text = getString(R.string.tir) + ": " + rh.gs(R.string.calculation_in_progress) })
|
||||
binding.activity.addView(TextView(this).apply { text = getString(R.string.activitymonitor) + ": " + rh.gs(R.string.calculation_in_progress) })
|
||||
|
||||
Thread {
|
||||
val tdds = tddCalculator.stats()
|
||||
runOnUiThread { binding.tdds.text = tdds }
|
||||
val tdds = tddCalculator.stats(this)
|
||||
runOnUiThread {
|
||||
binding.tdds.removeAllViews()
|
||||
binding.tdds.addView(tdds)
|
||||
}
|
||||
}.start()
|
||||
Thread {
|
||||
val tir = tirCalculator.stats()
|
||||
runOnUiThread { binding.tir.text = tir }
|
||||
val tir = tirCalculator.stats(this)
|
||||
runOnUiThread {
|
||||
binding.tir.removeAllViews()
|
||||
binding.tir.addView(tir)
|
||||
}
|
||||
}.start()
|
||||
Thread {
|
||||
val activity = activityMonitor.stats()
|
||||
runOnUiThread { binding.activity.text = activity }
|
||||
val activity = activityMonitor.stats(this)
|
||||
runOnUiThread {
|
||||
binding.activity.removeAllViews()
|
||||
binding.activity.addView(activity)
|
||||
}
|
||||
}.start()
|
||||
|
||||
binding.ok.setOnClickListener { finish() }
|
||||
|
|
|
@ -43,9 +43,9 @@ class SurveyActivity : NoSplashAppCompatActivity() {
|
|||
val profileList = profileStore?.getProfileList() ?: return
|
||||
binding.spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList)
|
||||
|
||||
binding.tdds.text = tddCalculator.stats()
|
||||
binding.tir.text = tirCalculator.stats()
|
||||
binding.activity.text = activityMonitor.stats()
|
||||
//binding.tdds.text = tddCalculator.stats()
|
||||
//binding.tir.text = tirCalculator.stats()
|
||||
//binding.activity.text = activityMonitor.stats()
|
||||
|
||||
binding.profile.setOnClickListener {
|
||||
val age = SafeParse.stringToDouble(binding.age.text.toString())
|
||||
|
@ -104,7 +104,7 @@ class SurveyActivity : NoSplashAppCompatActivity() {
|
|||
.addOnCompleteListener(this) { task ->
|
||||
if (task.isSuccessful) {
|
||||
aapsLogger.debug(LTag.CORE, "signInAnonymously:success")
|
||||
//val user = auth.currentUser // TODO: do we need this, seems unused?
|
||||
//val user = auth.currentUser // do we need this, seems unused?
|
||||
|
||||
val database = FirebaseDatabase.getInstance().reference
|
||||
database.child("survey").child(r.id).setValue(r)
|
||||
|
|
|
@ -2,12 +2,14 @@ package info.nightscout.androidaps.activities
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.fragments.*
|
||||
import info.nightscout.androidaps.databinding.TreatmentsFragmentBinding
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import javax.inject.Inject
|
||||
|
@ -23,49 +25,34 @@ class TreatmentsActivity : NoSplashAppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
binding = TreatmentsFragmentBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
//binding.tempBasals.visibility = buildHelper.isEngineeringMode().toVisibility()
|
||||
//binding.extendedBoluses.visibility = (buildHelper.isEngineeringMode() && !activePlugin.activePump.isFakingTempsByExtendedBoluses).toVisibility()
|
||||
|
||||
// Use index, TabItems crashes with an id
|
||||
val useFakeTempBasal = activePlugin.activePump.isFakingTempsByExtendedBoluses
|
||||
binding.treatmentsTabs.getTabAt(1)?.view?.visibility = useFakeTempBasal.toVisibility()
|
||||
|
||||
binding.treatments.setOnClickListener {
|
||||
setFragment(TreatmentsBolusCarbsFragment())
|
||||
setBackgroundColorOnSelected(it)
|
||||
supportActionBar?.title = rh.gs(R.string.carbs_and_bolus)
|
||||
}
|
||||
binding.extendedBoluses.setOnClickListener {
|
||||
setFragment(TreatmentsExtendedBolusesFragment())
|
||||
setBackgroundColorOnSelected(it)
|
||||
supportActionBar?.title = rh.gs(R.string.extended_bolus)
|
||||
}
|
||||
binding.tempBasals.setOnClickListener {
|
||||
setFragment(TreatmentsTemporaryBasalsFragment())
|
||||
setBackgroundColorOnSelected(it)
|
||||
supportActionBar?.title = rh.gs(R.string.tempbasal_label)
|
||||
}
|
||||
binding.tempTargets.setOnClickListener {
|
||||
setFragment(TreatmentsTempTargetFragment())
|
||||
setBackgroundColorOnSelected(it)
|
||||
supportActionBar?.title = rh.gs(R.string.tempt_targets)
|
||||
}
|
||||
binding.profileSwitches.setOnClickListener {
|
||||
setFragment(TreatmentsProfileSwitchFragment())
|
||||
setBackgroundColorOnSelected(it)
|
||||
supportActionBar?.title = rh.gs(R.string.profile_changes)
|
||||
}
|
||||
binding.careportal.setOnClickListener {
|
||||
setFragment(TreatmentsCareportalFragment())
|
||||
setBackgroundColorOnSelected(it)
|
||||
supportActionBar?.title = rh.gs(R.string.careportal)
|
||||
}
|
||||
binding.userentry.setOnClickListener {
|
||||
setFragment(TreatmentsUserEntryFragment())
|
||||
setBackgroundColorOnSelected(it)
|
||||
supportActionBar?.title = rh.gs(R.string.user_action)
|
||||
}
|
||||
setFragment(TreatmentsBolusCarbsFragment())
|
||||
setBackgroundColorOnSelected(binding.treatments)
|
||||
setSupportActionBar(binding.toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.title = rh.gs(R.string.carbs_and_bolus)
|
||||
|
||||
binding.treatmentsTabs.addOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
val fragment = when (tab.position) {
|
||||
0 -> TreatmentsBolusCarbsFragment::class.java
|
||||
1 -> TreatmentsExtendedBolusesFragment::class.java
|
||||
2 -> TreatmentsTemporaryBasalsFragment::class.java
|
||||
3 -> TreatmentsTempTargetFragment::class.java
|
||||
4 -> TreatmentsProfileSwitchFragment::class.java
|
||||
5 -> TreatmentsCareportalFragment::class.java
|
||||
else -> TreatmentsUserEntryFragment::class.java
|
||||
}
|
||||
setFragment(fragment.newInstance())
|
||||
supportActionBar?.title = tab.contentDescription
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab) {}
|
||||
override fun onTabReselected(tab: TabLayout.Tab) {}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -86,15 +73,4 @@ class TreatmentsActivity : NoSplashAppCompatActivity() {
|
|||
.commit()
|
||||
}
|
||||
|
||||
private fun setBackgroundColorOnSelected(selected: View) {
|
||||
binding.treatments.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.extendedBoluses.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.tempBasals.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.tempTargets.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.profileSwitches.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.careportal.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.userentry.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
selected.setBackgroundColor(rh.gc(R.color.tabBgColorSelected))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,12 +3,8 @@ package info.nightscout.androidaps.activities.fragments
|
|||
import android.annotation.SuppressLint
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import android.widget.CompoundButton
|
||||
import android.view.ActionMode
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -18,6 +14,7 @@ import info.nightscout.androidaps.database.AppRepository
|
|||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
import info.nightscout.androidaps.database.entities.BolusCalculatorResult
|
||||
import info.nightscout.androidaps.database.entities.Carbs
|
||||
import info.nightscout.androidaps.database.entities.UserEntry
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
|
@ -28,9 +25,7 @@ import info.nightscout.androidaps.database.transactions.InvalidateCarbsTransacti
|
|||
import info.nightscout.androidaps.databinding.TreatmentsBolusCarbsFragmentBinding
|
||||
import info.nightscout.androidaps.databinding.TreatmentsBolusCarbsItemBinding
|
||||
import info.nightscout.androidaps.dialogs.WizardInfoDialog
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventTreatmentChange
|
||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.extensions.iobCalc
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
|
@ -39,9 +34,11 @@ import info.nightscout.androidaps.logging.UserEntryLogger
|
|||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
@ -72,8 +69,10 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
|
||||
private var _binding: TreatmentsBolusCarbsFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
private var menu: Menu? = null
|
||||
|
||||
class MealLink(
|
||||
val bolus: Bolus? = null,
|
||||
|
@ -82,23 +81,24 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
)
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private lateinit var actionHelper: ActionModeHelper<MealLink>
|
||||
private val millsToThePast = T.days(30).msecs()
|
||||
|
||||
private var selectedItems: SparseArray<MealLink> = SparseArray()
|
||||
private var showInvalidated = false
|
||||
private var removeActionMode: ActionMode? = null
|
||||
private var toolbar: Toolbar? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
TreatmentsBolusCarbsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
actionHelper = ActionModeHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(true)
|
||||
toolbar = activity?.findViewById(R.id.toolbar)
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recyclerview.emptyView = binding.noRecordsText
|
||||
binding.recyclerview.loadingView = binding.progressBar
|
||||
}
|
||||
|
||||
private fun bolusMealLinksWithInvalid(now: Long) = repository
|
||||
|
@ -127,8 +127,8 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
|
||||
fun swapAdapter() {
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
disposable +=
|
||||
binding.recyclerview.isLoading = true
|
||||
disposable +=
|
||||
if (showInvalidated)
|
||||
carbsMealLinksWithInvalid(now)
|
||||
.zipWith(bolusMealLinksWithInvalid(now)) { first, second -> first + second }
|
||||
|
@ -169,28 +169,18 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
.observeOn(aapsSchedulers.main)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.let { it.finish() }
|
||||
binding.recyclerview.adapter = null // avoid leaks
|
||||
_binding = null
|
||||
}
|
||||
|
@ -206,9 +196,9 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
val profile = profileFunction.getProfile() ?: return
|
||||
val ml = mealLinks[position]
|
||||
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(timestamp(ml), timestamp(mealLinks[position - 1]))
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(timestamp(ml))
|
||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(timestamp(ml), timestamp(mealLinks[position - 1]))
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(timestamp(ml), rh) else ""
|
||||
|
||||
// Metadata
|
||||
holder.binding.metadataLayout.visibility = (ml.bolusCalculatorResult != null && (ml.bolusCalculatorResult.isValid || showInvalidated)).toVisibility()
|
||||
|
@ -226,7 +216,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
holder.binding.bolusInvalid.visibility = bolus.isValid.not().toVisibility()
|
||||
val iob = bolus.iobCalc(activePlugin, System.currentTimeMillis(), profile.dia)
|
||||
if (iob.iobContrib > 0.01) {
|
||||
holder.binding.iob.setTextColor(rh.gc(R.color.colorActive))
|
||||
holder.binding.iob.setTextColor(rh.gac(context , R.attr.activeColor))
|
||||
holder.binding.iob.text = rh.gs(R.string.formatinsulinunits, iob.iobContrib)
|
||||
holder.binding.iobLabel.visibility = View.VISIBLE
|
||||
holder.binding.iob.visibility = View.VISIBLE
|
||||
|
@ -236,13 +226,25 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
holder.binding.iobLabel.visibility = View.GONE
|
||||
holder.binding.iob.visibility = View.GONE
|
||||
}
|
||||
if (bolus.timestamp > dateUtil.now()) holder.binding.date.setTextColor(rh.gc(R.color.colorScheduled)) else holder.binding.date.setTextColor(holder.binding.carbs.currentTextColor)
|
||||
if (bolus.timestamp > dateUtil.now()) holder.binding.date.setTextColor(rh.gac(context, R.attr.scheduledColor)) else holder.binding.date.setTextColor(holder.binding.carbs
|
||||
.currentTextColor)
|
||||
holder.binding.mealOrCorrection.text =
|
||||
when (ml.bolus.type) {
|
||||
Bolus.Type.SMB -> "SMB"
|
||||
Bolus.Type.NORMAL -> rh.gs(R.string.mealbolus)
|
||||
Bolus.Type.PRIMING -> rh.gs(R.string.prime)
|
||||
}
|
||||
holder.binding.cbBolusRemove.visibility = (ml.bolus.isValid && actionHelper.isRemoving).toVisibility()
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbBolusRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, ml, value)
|
||||
}
|
||||
holder.binding.root.setOnClickListener {
|
||||
holder.binding.cbBolusRemove.toggle()
|
||||
actionHelper.updateSelection(position, ml, holder.binding.cbBolusRemove.isChecked)
|
||||
}
|
||||
holder.binding.cbBolusRemove.isChecked = actionHelper.isSelected(position)
|
||||
}
|
||||
}
|
||||
// Carbs
|
||||
holder.binding.carbsLayout.visibility = (ml.carbs != null && (ml.carbs.isValid || showInvalidated)).toVisibility()
|
||||
|
@ -253,26 +255,22 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
holder.binding.carbsNs.visibility = (carbs.interfaceIDs.nightscoutId != null).toVisibility()
|
||||
holder.binding.carbsPump.visibility = (carbs.interfaceIDs.pumpId != null).toVisibility()
|
||||
holder.binding.carbsInvalid.visibility = carbs.isValid.not().toVisibility()
|
||||
}
|
||||
holder.binding.cbBolusRemove.visibility = (ml.bolus?.isValid == true && removeActionMode != null).toVisibility()
|
||||
holder.binding.cbCarbsRemove.visibility = (ml.carbs?.isValid == true && removeActionMode != null).toVisibility()
|
||||
if (removeActionMode != null) {
|
||||
val onChange = CompoundButton.OnCheckedChangeListener { _, value ->
|
||||
if (value) {
|
||||
selectedItems.put(position, ml)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
holder.binding.cbCarbsRemove.visibility = (ml.carbs.isValid && actionHelper.isRemoving).toVisibility()
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbCarbsRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, ml, value)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
holder.binding.root.setOnClickListener {
|
||||
holder.binding.cbBolusRemove.toggle()
|
||||
actionHelper.updateSelection(position, ml, holder.binding.cbBolusRemove.isChecked)
|
||||
}
|
||||
holder.binding.cbCarbsRemove.isChecked = actionHelper.isSelected(position)
|
||||
}
|
||||
holder.binding.cbBolusRemove.setOnCheckedChangeListener(onChange)
|
||||
holder.binding.cbBolusRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.cbCarbsRemove.setOnCheckedChangeListener(onChange)
|
||||
holder.binding.cbCarbsRemove.isChecked = selectedItems.get(position) != null
|
||||
}
|
||||
|
||||
holder.binding.calculation.tag = ml
|
||||
val nextTimestamp = if (mealLinks.size != position + 1) timestamp(mealLinks[position + 1]) else 0L
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDay(timestamp(ml), nextTimestamp).toVisibility()
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(timestamp(ml), nextTimestamp).toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount() = mealLinks.size
|
||||
|
@ -297,13 +295,18 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
this.menu = menu
|
||||
inflater.inflate(R.menu.menu_treatments_carbs_bolus, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
private fun updateMenuVisibility() {
|
||||
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
updateMenuVisibility()
|
||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_insulin, false) || !sp.getBoolean(R.string.key_ns_receive_carbs, false) || !buildHelper.isEngineeringMode()
|
||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||
val hasItems = (binding.recyclerview.adapter?.itemCount ?: 0) > 0
|
||||
|
@ -314,20 +317,21 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||
|
||||
R.id.nav_show_invalidated -> {
|
||||
showInvalidated = true
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_hide_invalidated -> {
|
||||
showInvalidated = false
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -423,36 +427,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.menu_delete_selection, menu)
|
||||
selectedItems.clear()
|
||||
mode.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.remove_selected -> {
|
||||
removeSelected()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
removeActionMode = null
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<MealLink>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val mealLink = selectedItems.valueAt(0)
|
||||
val bolus = mealLink.bolus
|
||||
|
@ -467,40 +442,38 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
fun removeSelected() {
|
||||
if (selectedItems.size() > 0)
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach { _, ml ->
|
||||
ml.bolus?.let { bolus ->
|
||||
uel.log(
|
||||
Action.BOLUS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(bolus.timestamp),
|
||||
ValueWithUnit.Insulin(bolus.amount)
|
||||
private fun removeSelected(selectedItems: SparseArray<MealLink>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, ml ->
|
||||
ml.bolus?.let { bolus ->
|
||||
uel.log(
|
||||
Action.BOLUS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(bolus.timestamp),
|
||||
ValueWithUnit.Insulin(bolus.amount)
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateBolusTransaction(bolus.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it) }
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateBolusTransaction(bolus.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bolus $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating bolus", it) }
|
||||
)
|
||||
}
|
||||
ml.carbs?.let { carb ->
|
||||
uel.log(
|
||||
Action.CARBS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(carb.timestamp),
|
||||
ValueWithUnit.Gram(carb.amount.toInt())
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateCarbsTransaction(carb.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
})
|
||||
}
|
||||
else
|
||||
removeActionMode?.finish()
|
||||
ml.carbs?.let { carb ->
|
||||
uel.log(
|
||||
Action.CARBS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(carb.timestamp),
|
||||
ValueWithUnit.Gram(carb.amount.toInt())
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateCarbsTransaction(carb.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated carbs $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating carbs", it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,39 +3,33 @@ package info.nightscout.androidaps.activities.fragments
|
|||
import android.os.Bundle
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import android.view.ActionMode
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.InvalidateAAPSStartedTherapyEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InvalidateTherapyEventTransaction
|
||||
import info.nightscout.androidaps.databinding.TreatmentsCareportalFragmentBinding
|
||||
import info.nightscout.androidaps.databinding.TreatmentsCareportalItemBinding
|
||||
import info.nightscout.androidaps.events.EventTherapyEventChange
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsCareportalFragment.RecyclerViewAdapter.TherapyEventsViewHolder
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.Translator
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.core.Completable
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
|
@ -59,26 +53,28 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var _binding: TreatmentsCareportalFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var menu: Menu? = null
|
||||
private val disposable = CompositeDisposable()
|
||||
private val millsToThePast = T.days(30).msecs()
|
||||
private var selectedItems: SparseArray<TherapyEvent> = SparseArray()
|
||||
private lateinit var actionHelper: ActionModeHelper<TherapyEvent>
|
||||
private var showInvalidated = false
|
||||
private var toolbar: Toolbar? = null
|
||||
private var removeActionMode: ActionMode? = null
|
||||
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
TreatmentsCareportalFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
toolbar = activity?.findViewById(R.id.toolbar)
|
||||
actionHelper = ActionModeHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(true)
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recyclerview.emptyView = binding.noRecordsText
|
||||
binding.recyclerview.loadingView = binding.progressBar
|
||||
}
|
||||
|
||||
private fun refreshFromNightscout() {
|
||||
|
@ -111,6 +107,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
|
||||
fun swapAdapter() {
|
||||
val now = System.currentTimeMillis()
|
||||
binding.recyclerview.isLoading = true
|
||||
disposable +=
|
||||
if (showInvalidated)
|
||||
repository
|
||||
|
@ -133,23 +130,18 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
.observeOn(aapsSchedulers.main)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.let { it.finish() }
|
||||
binding.recyclerview.adapter = null // avoid leaks
|
||||
_binding = null
|
||||
}
|
||||
|
@ -165,27 +157,24 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
val therapyEvent = therapyList[position]
|
||||
holder.binding.ns.visibility = (therapyEvent.interfaceIDs.nightscoutId != null).toVisibility()
|
||||
holder.binding.invalid.visibility = therapyEvent.isValid.not().toVisibility()
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(therapyEvent.timestamp, therapyList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(therapyEvent.timestamp)
|
||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(therapyEvent.timestamp, therapyList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(therapyEvent.timestamp, rh) else ""
|
||||
holder.binding.time.text = dateUtil.timeString(therapyEvent.timestamp)
|
||||
holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else dateUtil.niceTimeScalar(therapyEvent.duration, rh)
|
||||
holder.binding.note.text = therapyEvent.note
|
||||
holder.binding.type.text = translator.translate(therapyEvent.type)
|
||||
holder.binding.cbRemove.visibility = (therapyEvent.isValid && removeActionMode != null).toVisibility()
|
||||
if (removeActionMode != null) {
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
if (value) {
|
||||
selectedItems.put(position, therapyEvent)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.cbRemove.visibility = (therapyEvent.isValid && actionHelper.isRemoving).toVisibility()
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, therapyEvent, value)
|
||||
}
|
||||
holder.binding.root.setOnClickListener {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, therapyEvent, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
val nextTimestamp = if (therapyList.size != position + 1) therapyList[position + 1].timestamp else 0L
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDay(therapyEvent.timestamp, nextTimestamp).toVisibility()
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(therapyEvent.timestamp, nextTimestamp).toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount() = therapyList.size
|
||||
|
@ -198,35 +187,41 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
this.menu = menu
|
||||
inflater.inflate(R.menu.menu_treatments_careportal, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
updateMenuVisibility()
|
||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_therapy_events, false) || !buildHelper.isEngineeringMode()
|
||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
private fun updateMenuVisibility() {
|
||||
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||
|
||||
R.id.nav_show_invalidated -> {
|
||||
showInvalidated = true
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_hide_invalidated -> {
|
||||
showInvalidated = false
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -243,36 +238,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
else -> false
|
||||
}
|
||||
|
||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.menu_delete_selection, menu)
|
||||
selectedItems.clear()
|
||||
mode.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.remove_selected -> {
|
||||
removeSelected()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
removeActionMode = null
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<TherapyEvent>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val therapyEvent = selectedItems.valueAt(0)
|
||||
return rh.gs(R.string.eventtype) + ": " + translator.translate(therapyEvent.type) + "\n" +
|
||||
|
@ -282,27 +248,24 @@ class TreatmentsCareportalFragment : DaggerFragment() {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected() {
|
||||
if (selectedItems.size() > 0)
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach { _, therapyEvent ->
|
||||
uel.log(
|
||||
Action.CAREPORTAL_REMOVED, Sources.Treatments, therapyEvent.note,
|
||||
ValueWithUnit.Timestamp(therapyEvent.timestamp),
|
||||
ValueWithUnit.TherapyEventType(therapyEvent.type)
|
||||
private fun removeSelected(selectedItems: SparseArray<TherapyEvent>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, therapyEvent ->
|
||||
uel.log(
|
||||
Action.CAREPORTAL_REMOVED, Sources.Treatments, therapyEvent.note,
|
||||
ValueWithUnit.Timestamp(therapyEvent.timestamp),
|
||||
ValueWithUnit.TherapyEventType(therapyEvent.type)
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateTherapyEventTransaction(therapyEvent.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated therapy event $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) }
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateTherapyEventTransaction(therapyEvent.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated therapy event $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating therapy event", it) }
|
||||
)
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
})
|
||||
}
|
||||
else
|
||||
removeActionMode?.finish()
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,13 +4,12 @@ import android.annotation.SuppressLint
|
|||
import android.os.Bundle
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import android.view.ActionMode
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
|
@ -26,20 +25,20 @@ import info.nightscout.androidaps.extensions.isInProgress
|
|||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsExtendedBolusesFragment.RecyclerViewAdapter.ExtendedBolusesViewHolder
|
||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -61,26 +60,32 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
private var _binding: TreatmentsExtendedbolusFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var selectedItems: SparseArray<ExtendedBolus> = SparseArray()
|
||||
private var menu: Menu? = null
|
||||
private lateinit var actionHelper: ActionModeHelper<ExtendedBolus>
|
||||
private var showInvalidated = false
|
||||
private var removeActionMode: ActionMode? = null
|
||||
private var toolbar: Toolbar? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
TreatmentsExtendedbolusFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
actionHelper = ActionModeHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(true)
|
||||
toolbar = activity?.findViewById(R.id.toolbar)
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recyclerview.emptyView = binding.noRecordsText
|
||||
binding.recyclerview.loadingView = binding.progressBar
|
||||
}
|
||||
|
||||
fun swapAdapter() {
|
||||
val now = System.currentTimeMillis()
|
||||
binding.recyclerview.isLoading = true
|
||||
disposable += if (showInvalidated)
|
||||
repository
|
||||
.getExtendedBolusDataIncludingInvalidFromTime(now - millsToThePast, false)
|
||||
|
@ -97,7 +102,6 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
swapAdapter()
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
|
@ -108,13 +112,13 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
@Synchronized
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.let { it.finish() }
|
||||
binding.recyclerview.adapter = null // avoid leaks
|
||||
_binding = null
|
||||
}
|
||||
|
@ -131,13 +135,12 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
holder.binding.ns.visibility = (extendedBolus.interfaceIDs.nightscoutId != null).toVisibility()
|
||||
holder.binding.ph.visibility = (extendedBolus.interfaceIDs.pumpId != null).toVisibility()
|
||||
holder.binding.invalid.visibility = extendedBolus.isValid.not().toVisibility()
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(extendedBolus.timestamp, extendedBolusList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(extendedBolus.timestamp)
|
||||
@SuppressLint("SetTextI18n")
|
||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(extendedBolus.timestamp, extendedBolusList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(extendedBolus.timestamp, rh) else ""
|
||||
if (extendedBolus.isInProgress(dateUtil)) {
|
||||
holder.binding.time.text = dateUtil.timeString(extendedBolus.timestamp)
|
||||
holder.binding.time.setTextColor(rh.gc(R.color.colorActive))
|
||||
holder.binding.time.setTextColor(rh.gac(context , R.attr.activeColor))
|
||||
} else {
|
||||
holder.binding.time.text = dateUtil.timeRangeString(extendedBolus.timestamp, extendedBolus.end)
|
||||
holder.binding.time.setTextColor(holder.binding.insulin.currentTextColor)
|
||||
|
@ -148,21 +151,20 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
val iob = extendedBolus.iobCalc(System.currentTimeMillis(), profile, activePlugin.activeInsulin)
|
||||
holder.binding.iob.text = rh.gs(R.string.formatinsulinunits, iob.iob)
|
||||
holder.binding.ratio.text = rh.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
||||
if (iob.iob != 0.0) holder.binding.iob.setTextColor(rh.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.insulin.currentTextColor)
|
||||
holder.binding.cbRemove.visibility = (extendedBolus.isValid && removeActionMode != null).toVisibility()
|
||||
if (removeActionMode != null) {
|
||||
if (iob.iob != 0.0) holder.binding.iob.setTextColor(rh.gac(context , R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.insulin.currentTextColor)
|
||||
holder.binding.cbRemove.visibility = (extendedBolus.isValid && actionHelper.isRemoving).toVisibility()
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
if (value) {
|
||||
selectedItems.put(position, extendedBolus)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
actionHelper.updateSelection(position, extendedBolus, value)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.root.setOnClickListener {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, extendedBolus, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
}
|
||||
val nextTimestamp = if (extendedBolusList.size != position + 1) extendedBolusList[position + 1].timestamp else 0L
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDay(extendedBolus.timestamp, nextTimestamp).toVisibility()
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(extendedBolus.timestamp, nextTimestamp).toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount() = extendedBolusList.size
|
||||
|
@ -175,33 +177,38 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
this.menu = menu
|
||||
inflater.inflate(R.menu.menu_treatments_extended_bolus, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
private fun updateMenuVisibility() {
|
||||
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
updateMenuVisibility()
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||
|
||||
R.id.nav_show_invalidated -> {
|
||||
showInvalidated = true
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_hide_invalidated -> {
|
||||
showInvalidated = false
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -209,36 +216,7 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.menu_delete_selection, menu)
|
||||
selectedItems.clear()
|
||||
mode.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.remove_selected -> {
|
||||
removeSelected()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
removeActionMode = null
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<ExtendedBolus>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val bolus = selectedItems.valueAt(0)
|
||||
return rh.gs(R.string.extended_bolus) + "\n" +
|
||||
|
@ -247,27 +225,25 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected() {
|
||||
if (selectedItems.size() > 0)
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach { _, extendedBolus ->
|
||||
uel.log(
|
||||
Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(extendedBolus.timestamp),
|
||||
ValueWithUnit.Insulin(extendedBolus.amount),
|
||||
ValueWithUnit.UnitPerHour(extendedBolus.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(extendedBolus.duration).toInt())
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) })
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
})
|
||||
}
|
||||
else
|
||||
removeActionMode?.finish()
|
||||
private fun removeSelected(selectedItems: SparseArray<ExtendedBolus>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, extendedBolus ->
|
||||
uel.log(
|
||||
Action.EXTENDED_BOLUS_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(extendedBolus.timestamp),
|
||||
ValueWithUnit.Insulin(extendedBolus.amount),
|
||||
ValueWithUnit.UnitPerHour(extendedBolus.rate),
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(extendedBolus.duration).toInt())
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateExtendedBolusTransaction(extendedBolus.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed extended bolus $extendedBolus") },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating extended bolus", it) })
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import android.view.ActionMode
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -23,7 +22,6 @@ import info.nightscout.androidaps.databinding.TreatmentsProfileswitchItemBinding
|
|||
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
||||
import info.nightscout.androidaps.events.EventEffectiveProfileSwitchChanged
|
||||
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.extensions.getCustomizedName
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
|
@ -32,9 +30,11 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR
|
|||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
|
||||
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
@ -63,26 +63,29 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var _binding: TreatmentsProfileswitchFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var menu: Menu? = null
|
||||
private lateinit var actionHelper: ActionModeHelper<ProfileSealed>
|
||||
private val disposable = CompositeDisposable()
|
||||
private val millsToThePast = T.days(30).msecs()
|
||||
private var selectedItems: SparseArray<ProfileSealed> = SparseArray()
|
||||
private var showInvalidated = false
|
||||
private var removeActionMode: ActionMode? = null
|
||||
private var toolbar: Toolbar? = null
|
||||
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
TreatmentsProfileswitchFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
actionHelper = ActionModeHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(true)
|
||||
toolbar = activity?.findViewById(R.id.toolbar)
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recyclerview.emptyView = binding.noRecordsText
|
||||
binding.recyclerview.loadingView = binding.progressBar
|
||||
}
|
||||
|
||||
private fun refreshFromNightscout() {
|
||||
|
@ -127,7 +130,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
|
||||
fun swapAdapter() {
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
binding.recyclerview.isLoading = true
|
||||
disposable +=
|
||||
if (showInvalidated)
|
||||
profileSwitchWithInvalid(now)
|
||||
|
@ -164,13 +167,13 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
@Synchronized
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.finish()
|
||||
binding.recyclerview.adapter = null // avoid leaks
|
||||
_binding = null
|
||||
}
|
||||
|
@ -184,36 +187,35 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
val profileSwitch = profileSwitchList[position]
|
||||
holder.binding.ph.visibility = (profileSwitch is ProfileSealed.EPS).toVisibility()
|
||||
holder.binding.ns.visibility = (profileSwitch.interfaceIDs_backing?.nightscoutId != null).toVisibility()
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(profileSwitch.timestamp, profileSwitchList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(profileSwitch.timestamp)
|
||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(profileSwitch.timestamp, profileSwitchList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(profileSwitch.timestamp, rh) else ""
|
||||
holder.binding.time.text = dateUtil.timeString(profileSwitch.timestamp)
|
||||
holder.binding.duration.text = rh.gs(R.string.format_mins, T.msecs(profileSwitch.duration ?: 0L).mins())
|
||||
holder.binding.name.text =
|
||||
if (profileSwitch is ProfileSealed.PS) profileSwitch.value.getCustomizedName() else if (profileSwitch is ProfileSealed.EPS) profileSwitch.value.originalCustomizedName else ""
|
||||
if (profileSwitch.isInProgress(dateUtil)) holder.binding.date.setTextColor(rh.gc(R.color.colorActive))
|
||||
if (profileSwitch.isInProgress(dateUtil)) holder.binding.date.setTextColor(rh.gac(context , R.attr.activeColor))
|
||||
else holder.binding.date.setTextColor(holder.binding.duration.currentTextColor)
|
||||
holder.binding.clone.tag = profileSwitch
|
||||
holder.binding.name.tag = profileSwitch
|
||||
holder.binding.date.tag = profileSwitch
|
||||
holder.binding.invalid.visibility = profileSwitch.isValid.not().toVisibility()
|
||||
holder.binding.duration.visibility = (profileSwitch.duration != 0L && profileSwitch.duration != null).toVisibility()
|
||||
holder.binding.cbRemove.visibility = (removeActionMode != null && profileSwitch is ProfileSealed.PS).toVisibility()
|
||||
if (removeActionMode != null) {
|
||||
holder.binding.cbRemove.visibility = (actionHelper.isRemoving && profileSwitch is ProfileSealed.PS).toVisibility()
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
if (value) {
|
||||
selectedItems.put(position, profileSwitch)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
actionHelper.updateSelection(position, profileSwitch, value)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.root.setOnClickListener {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, profileSwitch, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
}
|
||||
holder.binding.clone.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
|
||||
holder.binding.spacer.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
|
||||
val nextTimestamp = if (profileSwitchList.size != position + 1) profileSwitchList[position + 1].timestamp else 0L
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDay(profileSwitch.timestamp, nextTimestamp).toVisibility()
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(profileSwitch.timestamp, nextTimestamp).toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount() = profileSwitchList.size
|
||||
|
@ -273,13 +275,18 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
this.menu = menu
|
||||
inflater.inflate(R.menu.menu_treatments_profile_switch, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
private fun updateMenuVisibility() {
|
||||
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
updateMenuVisibility()
|
||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_profile_switch, false) || !buildHelper.isEngineeringMode()
|
||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||
|
||||
|
@ -288,20 +295,21 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||
|
||||
R.id.nav_show_invalidated -> {
|
||||
showInvalidated = true
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_hide_invalidated -> {
|
||||
showInvalidated = false
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -313,36 +321,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
else -> false
|
||||
}
|
||||
|
||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.menu_delete_selection, menu)
|
||||
selectedItems.clear()
|
||||
mode.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.remove_selected -> {
|
||||
removeSelected()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
removeActionMode = null
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<ProfileSealed>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val profileSwitch = selectedItems.valueAt(0)
|
||||
return rh.gs(R.string.careportal_profileswitch) + ": " + profileSwitch.profileName + "\n" + rh.gs(R.string.date) + ": " + dateUtil.dateAndTimeString(profileSwitch.timestamp)
|
||||
|
@ -350,25 +329,22 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected() {
|
||||
if (selectedItems.size() > 0)
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach { _, profileSwitch ->
|
||||
uel.log(
|
||||
Action.PROFILE_SWITCH_REMOVED, Sources.Treatments, profileSwitch.profileName,
|
||||
ValueWithUnit.Timestamp(profileSwitch.timestamp)
|
||||
private fun removeSelected(selectedItems: SparseArray<ProfileSealed>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, profileSwitch ->
|
||||
uel.log(
|
||||
Action.PROFILE_SWITCH_REMOVED, Sources.Treatments, profileSwitch.profileName,
|
||||
ValueWithUnit.Timestamp(profileSwitch.timestamp)
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateProfileSwitchTransaction(profileSwitch.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating ProfileSwitch", it) }
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateProfileSwitchTransaction(profileSwitch.id))
|
||||
.subscribe(
|
||||
{ result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated ProfileSwitch $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating ProfileSwitch", it) }
|
||||
)
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
})
|
||||
}
|
||||
else
|
||||
removeActionMode?.finish()
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,46 +4,41 @@ import android.annotation.SuppressLint
|
|||
import android.os.Bundle
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.database.transactions.InvalidateTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.databinding.TreatmentsTemptargetFragmentBinding
|
||||
import info.nightscout.androidaps.databinding.TreatmentsTemptargetItemBinding
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTempTargetFragment.RecyclerViewAdapter.TempTargetsViewHolder
|
||||
import info.nightscout.androidaps.events.EventEffectiveProfileSwitchChanged
|
||||
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.Translator
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.extensions.friendlyDescription
|
||||
import info.nightscout.androidaps.extensions.highValueToUnitsToString
|
||||
import info.nightscout.androidaps.extensions.lowValueToUnitsToString
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.core.Completable
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
|
@ -68,24 +63,28 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
private var _binding: TreatmentsTemptargetFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var menu: Menu? = null
|
||||
private lateinit var actionHelper: ActionModeHelper<TemporaryTarget>
|
||||
private val disposable = CompositeDisposable()
|
||||
private val millsToThePast = T.days(30).msecs()
|
||||
private var selectedItems: SparseArray<TemporaryTarget> = SparseArray()
|
||||
private var showInvalidated = false
|
||||
private var toolbar: Toolbar? = null
|
||||
private var removeActionMode: ActionMode? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
TreatmentsTemptargetFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
toolbar = activity?.findViewById(R.id.toolbar)
|
||||
actionHelper = ActionModeHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recyclerview.emptyView = binding.noRecordsText
|
||||
binding.recyclerview.loadingView = binding.progressBar
|
||||
}
|
||||
|
||||
private fun refreshFromNightscout() {
|
||||
|
@ -114,6 +113,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
|
||||
fun swapAdapter() {
|
||||
val now = System.currentTimeMillis()
|
||||
binding.recyclerview.isLoading = true
|
||||
disposable +=
|
||||
if (showInvalidated)
|
||||
repository
|
||||
|
@ -131,30 +131,23 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
swapAdapter()
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempTargetChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentUpdateGui::class.java) // TODO join with above
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.let { it.finish() }
|
||||
binding.recyclerview.adapter = null // avoid leaks
|
||||
_binding = null
|
||||
}
|
||||
|
@ -173,21 +166,20 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
val tempTarget = tempTargetList[position]
|
||||
holder.binding.ns.visibility = (tempTarget.interfaceIDs.nightscoutId != null).toVisibility()
|
||||
holder.binding.invalid.visibility = tempTarget.isValid.not().toVisibility()
|
||||
holder.binding.cbRemove.visibility = (tempTarget.isValid && removeActionMode != null).toVisibility()
|
||||
if (removeActionMode != null) {
|
||||
holder.binding.cbRemove.visibility = (tempTarget.isValid && actionHelper.isRemoving).toVisibility()
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
if (value) {
|
||||
selectedItems.put(position, tempTarget)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
actionHelper.updateSelection(position, tempTarget, value)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.root.setOnClickListener {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, tempTarget, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
}
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(tempTarget.timestamp, tempTargetList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(tempTarget.timestamp)
|
||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(tempTarget.timestamp, tempTargetList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(tempTarget.timestamp, rh) else ""
|
||||
holder.binding.time.text = dateUtil.timeRangeString(tempTarget.timestamp, tempTarget.end)
|
||||
holder.binding.duration.text = rh.gs(R.string.format_mins, T.msecs(tempTarget.duration).mins())
|
||||
holder.binding.low.text = tempTarget.lowValueToUnitsToString(units)
|
||||
|
@ -195,13 +187,13 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
holder.binding.reason.text = translator.translate(tempTarget.reason)
|
||||
holder.binding.time.setTextColor(
|
||||
when {
|
||||
tempTarget.id == currentlyActiveTarget?.id -> rh.gc(R.color.colorActive)
|
||||
tempTarget.timestamp > dateUtil.now() -> rh.gc(R.color.colorScheduled)
|
||||
tempTarget.id == currentlyActiveTarget?.id -> rh.gac(context , R.attr.activeColor)
|
||||
tempTarget.timestamp > dateUtil.now() -> rh.gac(context , R.attr.scheduledColor)
|
||||
else -> holder.binding.reasonColon.currentTextColor
|
||||
}
|
||||
)
|
||||
val nextTimestamp = if (tempTargetList.size != position + 1) tempTargetList[position + 1].timestamp else 0L
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDay(tempTarget.timestamp, nextTimestamp).toVisibility()
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(tempTarget.timestamp, nextTimestamp).toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount() = tempTargetList.size
|
||||
|
@ -213,39 +205,19 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun removeSelected() {
|
||||
if (selectedItems.size() > 0)
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach { _, tempTarget ->
|
||||
uel.log(
|
||||
Action.TT_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(tempTarget.timestamp),
|
||||
ValueWithUnit.TherapyEventTTReason(tempTarget.reason),
|
||||
ValueWithUnit.Mgdl(tempTarget.lowTarget),
|
||||
ValueWithUnit.Mgdl(tempTarget.highTarget).takeIf { tempTarget.lowTarget != tempTarget.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tempTarget.duration).toInt())
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateTemporaryTargetTransaction(tempTarget.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed temp target $tempTarget") },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it) })
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
})
|
||||
}
|
||||
else
|
||||
removeActionMode?.finish()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
this.menu = menu
|
||||
inflater.inflate(R.menu.menu_treatments_temp_target, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
private fun updateMenuVisibility() {
|
||||
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
updateMenuVisibility()
|
||||
val nsUploadOnly = !sp.getBoolean(R.string.key_ns_receive_temp_target, false) || !buildHelper.isEngineeringMode()
|
||||
menu.findItem(R.id.nav_refresh_ns)?.isVisible = !nsUploadOnly
|
||||
|
||||
|
@ -254,20 +226,21 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||
|
||||
R.id.nav_show_invalidated -> {
|
||||
showInvalidated = true
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_hide_invalidated -> {
|
||||
showInvalidated = false
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -279,36 +252,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
else -> false
|
||||
}
|
||||
|
||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.menu_delete_selection, menu)
|
||||
selectedItems.clear()
|
||||
mode.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.remove_selected -> {
|
||||
removeSelected()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
removeActionMode = null
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<TemporaryTarget>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val tempTarget = selectedItems.valueAt(0)
|
||||
return "${rh.gs(R.string.careportal_temporarytarget)}: ${tempTarget.friendlyDescription(profileFunction.getUnits(), rh)}\n" +
|
||||
|
@ -317,4 +261,26 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected(selectedItems: SparseArray<TemporaryTarget>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, tempTarget ->
|
||||
uel.log(
|
||||
Action.TT_REMOVED, Sources.Treatments,
|
||||
ValueWithUnit.Timestamp(tempTarget.timestamp),
|
||||
ValueWithUnit.TherapyEventTTReason(tempTarget.reason),
|
||||
ValueWithUnit.Mgdl(tempTarget.lowTarget),
|
||||
ValueWithUnit.Mgdl(tempTarget.highTarget).takeIf { tempTarget.lowTarget != tempTarget.highTarget },
|
||||
ValueWithUnit.Minute(TimeUnit.MILLISECONDS.toMinutes(tempTarget.duration).toInt())
|
||||
)
|
||||
disposable += repository.runTransactionForResult(InvalidateTemporaryTargetTransaction(tempTarget.id))
|
||||
.subscribe(
|
||||
{ aapsLogger.debug(LTag.DATABASE, "Removed temp target $tempTarget") },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary target", it) })
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
package info.nightscout.androidaps.activities.fragments
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
|
@ -23,7 +23,6 @@ import info.nightscout.androidaps.database.transactions.InvalidateExtendedBolusT
|
|||
import info.nightscout.androidaps.database.transactions.InvalidateTemporaryBasalTransaction
|
||||
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsFragmentBinding
|
||||
import info.nightscout.androidaps.databinding.TreatmentsTempbasalsItemBinding
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventTempBasalChange
|
||||
import info.nightscout.androidaps.extensions.iobCalc
|
||||
import info.nightscout.androidaps.extensions.toStringFull
|
||||
|
@ -31,18 +30,18 @@ import info.nightscout.androidaps.extensions.toTemporaryBasal
|
|||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.activities.fragments.TreatmentsTemporaryBasalsFragment.RecyclerViewAdapter.TempBasalsViewHolder
|
||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -65,24 +64,28 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
private var _binding: TreatmentsTempbasalsFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var menu: Menu? = null
|
||||
private lateinit var actionHelper: ActionModeHelper<TemporaryBasal>
|
||||
private val millsToThePast = T.days(30).msecs()
|
||||
private var selectedItems: SparseArray<TemporaryBasal> = SparseArray()
|
||||
private var showInvalidated = false
|
||||
private var toolbar: Toolbar? = null
|
||||
private var removeActionMode: ActionMode? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
TreatmentsTempbasalsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
toolbar = activity?.findViewById(R.id.toolbar)
|
||||
actionHelper = ActionModeHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(true)
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recyclerview.emptyView = binding.noRecordsText
|
||||
binding.recyclerview.loadingView = binding.progressBar
|
||||
}
|
||||
|
||||
private fun tempBasalsWithInvalid(now: Long) = repository
|
||||
|
@ -101,6 +104,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
|
||||
fun swapAdapter() {
|
||||
val now = System.currentTimeMillis()
|
||||
binding.recyclerview.isLoading = true
|
||||
disposable +=
|
||||
if (activePlugin.activePump.isFakingTempsByExtendedBoluses) {
|
||||
if (showInvalidated)
|
||||
|
@ -134,28 +138,22 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
swapAdapter()
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
removeActionMode?.let { it.finish() }
|
||||
binding.recyclerview.adapter = null // avoid leaks
|
||||
_binding = null
|
||||
}
|
||||
|
@ -172,10 +170,12 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
holder.binding.ph.visibility = (tempBasal.interfaceIDs.pumpId != null).toVisibility()
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(tempBasal.timestamp, tempBasalList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(tempBasal.timestamp)
|
||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(tempBasal.timestamp, tempBasalList[position - 1].timestamp)
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(tempBasal.timestamp, rh) else ""
|
||||
if (tempBasal.isInProgress) {
|
||||
holder.binding.time.text = dateUtil.timeString(tempBasal.timestamp)
|
||||
holder.binding.time.setTextColor(rh.gc(R.color.colorActive))
|
||||
holder.binding.time.setTextColor(rh.gac(context, R.attr.activeColor))
|
||||
} else {
|
||||
holder.binding.time.text = dateUtil.timeRangeString(tempBasal.timestamp, tempBasal.end)
|
||||
holder.binding.time.setTextColor(holder.binding.duration.currentTextColor)
|
||||
|
@ -192,21 +192,20 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
holder.binding.suspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.PUMP_SUSPEND).toVisibility()
|
||||
holder.binding.emulatedSuspendFlag.visibility = (tempBasal.type == TemporaryBasal.Type.EMULATED_PUMP_SUSPEND).toVisibility()
|
||||
holder.binding.superBolusFlag.visibility = (tempBasal.type == TemporaryBasal.Type.SUPERBOLUS).toVisibility()
|
||||
if (abs(iob.basaliob) > 0.01) holder.binding.iob.setTextColor(rh.gc(R.color.colorActive)) else holder.binding.iob.setTextColor(holder.binding.duration.currentTextColor)
|
||||
holder.binding.cbRemove.visibility = (tempBasal.isValid && removeActionMode != null).toVisibility()
|
||||
if (removeActionMode != null) {
|
||||
if (abs(iob.basaliob) > 0.01) holder.binding.iob.setTextColor(rh.gac(context, R.attr.activeColor)) else holder.binding.iob.setTextColor(holder.binding.duration.currentTextColor)
|
||||
holder.binding.cbRemove.visibility = (tempBasal.isValid && actionHelper.isRemoving).toVisibility()
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
if (value) {
|
||||
selectedItems.put(position, tempBasal)
|
||||
} else {
|
||||
selectedItems.remove(position)
|
||||
}
|
||||
removeActionMode?.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
actionHelper.updateSelection(position, tempBasal, value)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
|
||||
holder.binding.root.setOnClickListener {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, tempBasal, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
}
|
||||
val nextTimestamp = if (tempBasalList.size != position + 1) tempBasalList[position + 1].timestamp else 0L
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDay(tempBasal.timestamp, nextTimestamp).toVisibility()
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(tempBasal.timestamp, nextTimestamp).toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount() = tempBasalList.size
|
||||
|
@ -220,69 +219,46 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
this.menu = menu
|
||||
inflater.inflate(R.menu.menu_treatments_temp_basal, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
private fun updateMenuVisibility() {
|
||||
menu?.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu?.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_hide_invalidated)?.isVisible = showInvalidated
|
||||
menu.findItem(R.id.nav_show_invalidated)?.isVisible = !showInvalidated
|
||||
updateMenuVisibility()
|
||||
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
R.id.nav_remove_items -> {
|
||||
removeActionMode = toolbar?.startActionMode(RemoveActionModeCallback())
|
||||
true
|
||||
}
|
||||
R.id.nav_remove_items -> actionHelper.startRemove()
|
||||
|
||||
R.id.nav_show_invalidated -> {
|
||||
showInvalidated = true
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_hide_invalidated -> {
|
||||
showInvalidated = false
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.hide_invalidated_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
inner class RemoveActionModeCallback : ActionMode.Callback {
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu?): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.menu_delete_selection, menu)
|
||||
selectedItems.clear()
|
||||
mode.title = rh.gs(R.string.count_selected, selectedItems.size())
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.remove_selected -> {
|
||||
removeSelected()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
removeActionMode = null
|
||||
binding.recyclerview.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConfirmationText(): String {
|
||||
private fun getConfirmationText(selectedItems: SparseArray<TemporaryBasal>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val tempBasal = selectedItems.valueAt(0)
|
||||
val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED
|
||||
|
@ -294,11 +270,11 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected() {
|
||||
private fun removeSelected(selectedItems: SparseArray<TemporaryBasal>) {
|
||||
if (selectedItems.size() > 0)
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(), Runnable {
|
||||
selectedItems.forEach {_, tempBasal ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, tempBasal ->
|
||||
var extendedBolus: ExtendedBolus? = null
|
||||
val isFakeExtended = tempBasal.type == TemporaryBasal.Type.FAKE_EXTENDED
|
||||
if (isFakeExtended) {
|
||||
|
@ -330,10 +306,8 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
|
|||
{ aapsLogger.error(LTag.DATABASE, "Error while invalidating temporary basal", it) })
|
||||
}
|
||||
}
|
||||
removeActionMode?.finish()
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
else
|
||||
removeActionMode?.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,23 +13,22 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
|||
import info.nightscout.androidaps.databinding.TreatmentsUserEntryFragmentBinding
|
||||
import info.nightscout.androidaps.databinding.TreatmentsUserEntryItemBinding
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.events.EventTreatmentUpdateGui
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.Translator
|
||||
import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class TreatmentsUserEntryFragment : DaggerFragment() {
|
||||
|
@ -47,9 +46,9 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
|||
@Inject lateinit var userEntryPresentationHelper: UserEntryPresentationHelper
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private val millsToThePastFiltered = T.days(30).msecs()
|
||||
private val millsToThePastUnFiltered = T.days(3).msecs()
|
||||
private var menu: Menu? = null
|
||||
private var showLoop = false
|
||||
private var _binding: TreatmentsUserEntryFragmentBinding? = null
|
||||
|
||||
|
@ -64,9 +63,11 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
|||
setHasOptionsMenu(true)
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
binding.recyclerview.emptyView = binding.noRecordsText
|
||||
binding.recyclerview.loadingView = binding.progressBar
|
||||
}
|
||||
|
||||
fun exportUserEnteries() {
|
||||
private fun exportUserEntries() {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.ue_export_to_csv) + "?") {
|
||||
uel.log(Action.EXPORT_CSV, Sources.Treatments)
|
||||
|
@ -77,6 +78,7 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
|||
|
||||
fun swapAdapter() {
|
||||
val now = System.currentTimeMillis()
|
||||
binding.recyclerview.isLoading = true
|
||||
disposable +=
|
||||
if (showLoop)
|
||||
repository
|
||||
|
@ -94,16 +96,10 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
swapAdapter()
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentUpdateGui::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -128,19 +124,18 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
|||
|
||||
override fun onBindViewHolder(holder: UserEntryViewHolder, position: Int) {
|
||||
val current = entries[position]
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(current.timestamp, entries[position - 1].timestamp)
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(current.timestamp)
|
||||
val newDay = position == 0 || !dateUtil.isSameDayGroup(current.timestamp, entries[position - 1].timestamp)
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(current.timestamp, rh) else ""
|
||||
holder.binding.time.text = dateUtil.timeStringWithSeconds(current.timestamp)
|
||||
holder.binding.action.text = userEntryPresentationHelper.actionToColoredString(current.action)
|
||||
holder.binding.notes.text = current.note
|
||||
holder.binding.notes.visibility = if (current.note != "") View.VISIBLE else View.GONE
|
||||
holder.binding.notes.visibility = (current.note != "").toVisibility()
|
||||
holder.binding.iconSource.setImageResource(userEntryPresentationHelper.iconId(current.source))
|
||||
holder.binding.iconSource.visibility = View.VISIBLE
|
||||
holder.binding.values.text = userEntryPresentationHelper.listToPresentationString(current.values)
|
||||
holder.binding.values.visibility = if (holder.binding.values.text != "") View.VISIBLE else View.GONE
|
||||
holder.binding.values.visibility = (holder.binding.values.text != "").toVisibility()
|
||||
val nextTimestamp = if (entries.size != position + 1) entries[position + 1].timestamp else 0L
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDay(current.timestamp, nextTimestamp).toVisibility()
|
||||
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(current.timestamp, nextTimestamp).toVisibility()
|
||||
}
|
||||
|
||||
inner class UserEntryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
@ -152,14 +147,18 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
this.menu = menu
|
||||
inflater.inflate(R.menu.menu_treatments_user_entry, menu)
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
menu.findItem(R.id.nav_hide_loop)?.isVisible = showLoop
|
||||
menu.findItem(R.id.nav_show_loop)?.isVisible = !showLoop
|
||||
private fun updateMenuVisibility() {
|
||||
menu?.findItem(R.id.nav_hide_loop)?.isVisible = showLoop
|
||||
menu?.findItem(R.id.nav_show_loop)?.isVisible = !showLoop
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
updateMenuVisibility()
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
|
@ -167,21 +166,26 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
|
|||
when (item.itemId) {
|
||||
R.id.nav_show_loop -> {
|
||||
showLoop = true
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_loop_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_hide_loop -> {
|
||||
showLoop = false
|
||||
rxBus.send(EventTreatmentUpdateGui())
|
||||
updateMenuVisibility()
|
||||
ToastUtils.showToastInUiThread(context, rh.gs(R.string.show_hide_records))
|
||||
swapAdapter()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.nav_export -> {
|
||||
exportUserEnteries()
|
||||
exportUserEntries()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,6 +60,11 @@ class CompatDBHelper @Inject constructor(
|
|||
rxBus.send(EventExtendedBolusChange())
|
||||
rxBus.send(EventNewHistoryData(timestamp, false))
|
||||
}
|
||||
it.filterIsInstance<EffectiveProfileSwitch>().firstOrNull()?.let { eps ->
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventEffectiveProfileSwitchChanged $eps")
|
||||
rxBus.send(EventEffectiveProfileSwitchChanged(eps))
|
||||
rxBus.send(EventNewHistoryData(eps.timestamp, false))
|
||||
}
|
||||
it.filterIsInstance<TemporaryTarget>().firstOrNull()?.let { tt ->
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange $tt")
|
||||
rxBus.send(EventTempTargetChange())
|
||||
|
@ -76,10 +81,6 @@ class CompatDBHelper @Inject constructor(
|
|||
aapsLogger.debug(LTag.DATABASE, "Firing EventProfileSwitchChanged $ps")
|
||||
rxBus.send(EventProfileSwitchChanged())
|
||||
}
|
||||
it.filterIsInstance<EffectiveProfileSwitch>().firstOrNull()?.let { eps ->
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventEffectiveProfileSwitchChanged $eps")
|
||||
rxBus.send(EventEffectiveProfileSwitchChanged(eps))
|
||||
}
|
||||
it.filterIsInstance<OfflineEvent>().firstOrNull()?.let { oe ->
|
||||
aapsLogger.debug(LTag.DATABASE, "Firing EventOfflineChange $oe")
|
||||
rxBus.send(EventOfflineChange())
|
||||
|
|
|
@ -8,8 +8,6 @@ import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
|
|||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMBDynamicISF.DetermineBasalAdapterSMBDynamicISFJS
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobOref1Thread
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
|
@ -21,6 +19,4 @@ abstract class APSModule {
|
|||
@ContributesAndroidInjector abstract fun determineBasalAdapterAMAJSInjector(): DetermineBasalAdapterAMAJS
|
||||
@ContributesAndroidInjector abstract fun determineBasalAdapterSMBJSInjector(): DetermineBasalAdapterSMBJS
|
||||
@ContributesAndroidInjector abstract fun determineBasalAdapterSMBAutoISFJSInjector(): DetermineBasalAdapterSMBDynamicISFJS
|
||||
@ContributesAndroidInjector abstract fun iobCobThreadInjector(): IobCobThread
|
||||
@ContributesAndroidInjector abstract fun iobCobOref1ThreadInjector(): IobCobOref1Thread
|
||||
}
|
|
@ -46,6 +46,7 @@ import javax.inject.Singleton
|
|||
OmnipodDashModule::class,
|
||||
OmnipodErosModule::class,
|
||||
APSModule::class,
|
||||
WorkflowModule::class,
|
||||
PreferencesModule::class,
|
||||
OverviewModule::class,
|
||||
DataClassesModule::class,
|
||||
|
|
|
@ -32,6 +32,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
|||
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin
|
||||
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin
|
||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||
import info.nightscout.androidaps.plugins.general.themes.ThemeSwitcherPlugin
|
||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
||||
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatusLinePlugin
|
||||
import info.nightscout.androidaps.plugins.insulin.InsulinLyumjevPlugin
|
||||
|
@ -393,6 +394,12 @@ abstract class PluginsModule {
|
|||
@IntKey(490)
|
||||
abstract fun bindConfigBuilderPlugin(plugin: ConfigBuilderPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
@IntKey(500)
|
||||
abstract fun bindThemeSwitcherPlugin(plugin: ThemeSwitcherPlugin): PluginBase
|
||||
|
||||
@Qualifier
|
||||
annotation class AllConfigs
|
||||
|
||||
|
|
|
@ -2,12 +2,11 @@ package info.nightscout.androidaps.di
|
|||
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.plugins.aps.loop.CarbSuggestionReceiver
|
||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBluetoothStateReceiver
|
||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBroadcastReceiver
|
||||
import info.nightscout.androidaps.plugins.aps.loop.CarbSuggestionReceiver
|
||||
import info.nightscout.androidaps.receivers.*
|
||||
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
abstract class ReceiversModule {
|
||||
|
@ -16,8 +15,7 @@ abstract class ReceiversModule {
|
|||
@ContributesAndroidInjector abstract fun contributesBTReceiver(): BTReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesKeepAliveWorker(): KeepAliveReceiver.KeepAliveWorker
|
||||
@ContributesAndroidInjector abstract fun contributesKeepAliveWorker(): KeepAliveWorker
|
||||
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver
|
||||
|
|
|
@ -2,10 +2,16 @@ package info.nightscout.androidaps.di
|
|||
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.widget.WidgetConfigureActivity
|
||||
import info.nightscout.androidaps.skins.SkinListPreference
|
||||
import info.nightscout.androidaps.widget.Widget
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
abstract class UIModule {
|
||||
|
||||
@ContributesAndroidInjector abstract fun skinListPreferenceInjector(): SkinListPreference
|
||||
@ContributesAndroidInjector abstract fun aapsWidgetInjector(): Widget
|
||||
@ContributesAndroidInjector abstract fun contributesWidgetConfigureActivity(): WidgetConfigureActivity
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package info.nightscout.androidaps.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.*
|
||||
import info.nightscout.androidaps.workflow.*
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
abstract class WorkflowModule {
|
||||
|
||||
@ContributesAndroidInjector abstract fun iobCobWorkerInjector(): IobCobOrefWorker
|
||||
@ContributesAndroidInjector abstract fun iobCobOref1WorkerInjector(): IobCobOref1Worker
|
||||
@ContributesAndroidInjector abstract fun prepareIobAutosensDataWorkerInjector(): PrepareIobAutosensGraphDataWorker
|
||||
@ContributesAndroidInjector abstract fun prepareBasalDataWorkerInjector(): PrepareBasalDataWorker
|
||||
@ContributesAndroidInjector abstract fun prepareTemporaryTargetDataWorkerInjector(): PrepareTemporaryTargetDataWorker
|
||||
@ContributesAndroidInjector abstract fun prepareTreatmentsDataWorkerInjector(): PrepareTreatmentsDataWorker
|
||||
@ContributesAndroidInjector abstract fun loadIobCobResultsWorkerInjector(): UpdateIobCobSensWorker
|
||||
@ContributesAndroidInjector abstract fun preparePredictionsWorkerInjector(): PreparePredictionsWorker
|
||||
@ContributesAndroidInjector abstract fun updateGraphAndIobWorkerInjector(): UpdateGraphWorker
|
||||
@ContributesAndroidInjector abstract fun prepareBgDataWorkerInjector(): PrepareBgDataWorker
|
||||
@ContributesAndroidInjector abstract fun prepareBucketedDataWorkerInjector(): PrepareBucketedDataWorker
|
||||
@ContributesAndroidInjector abstract fun loadBgDataWorkerInjector(): LoadBgDataWorker
|
||||
@ContributesAndroidInjector abstract fun invokeLoopWorkerInjector(): InvokeLoopWorker
|
||||
}
|
|
@ -64,7 +64,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
|||
binding.bg.setParams(savedInstanceState?.getDouble("bg")
|
||||
?: bg, 36.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
||||
binding.units.text = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl)
|
||||
binding.bg.editText?.id?.let { binding.bgLabel.labelFor = it }
|
||||
binding.bgLabel.labelFor = binding.bg.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -27,6 +27,8 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
|
|||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -50,6 +52,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var bolusTimer: BolusTimer
|
||||
@Inject lateinit var commandQueue: CommandQueue
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -58,6 +61,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
private const val FAV3_DEFAULT = 20
|
||||
}
|
||||
|
||||
private var queryingProtection = false
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private val textWatcher: TextWatcher = object : TextWatcher {
|
||||
|
@ -195,9 +199,9 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
binding.hypoTt.isChecked = false
|
||||
binding.activityTt.isChecked = false
|
||||
}
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.time.editText?.id?.let { binding.timeLabel.labelFor = it }
|
||||
binding.carbs.editText?.id?.let { binding.carbsLabel.labelFor = it }
|
||||
binding.durationLabel.labelFor = binding.duration.editTextId
|
||||
binding.timeLabel.labelFor = binding.time.editTextId
|
||||
binding.carbsLabel.labelFor = binding.carbs.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -230,8 +234,9 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
if (activitySelected)
|
||||
actions.add(
|
||||
rh.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(activityTT) + " " + unitLabel + " (" + rh.gs(R.string.format_mins, activityTTDuration) + ")").formatColor(
|
||||
context,
|
||||
rh,
|
||||
R.color.tempTargetConfirmation
|
||||
R.attr.tempTargetConfirmation
|
||||
)
|
||||
)
|
||||
val eatingSoonSelected = binding.eatingSoonTt.isChecked
|
||||
|
@ -240,27 +245,27 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
rh.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + rh.gs(
|
||||
R.string.format_mins,
|
||||
eatingSoonTTDuration
|
||||
) + ")").formatColor(rh, R.color.tempTargetConfirmation)
|
||||
) + ")").formatColor(context, rh, R.attr.tempTargetConfirmation)
|
||||
)
|
||||
val hypoSelected = binding.hypoTt.isChecked
|
||||
if (hypoSelected)
|
||||
actions.add(
|
||||
rh.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(hypoTT) + " " + unitLabel + " (" + rh.gs(R.string.format_mins, hypoTTDuration) + ")").formatColor(
|
||||
rh.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(hypoTT) + " " + unitLabel + " (" + rh.gs(R.string.format_mins, hypoTTDuration) + ")").formatColor( context,
|
||||
rh,
|
||||
R.color.tempTargetConfirmation
|
||||
R.attr.tempTargetConfirmation
|
||||
)
|
||||
)
|
||||
|
||||
val timeOffset = binding.time.value.toInt()
|
||||
if (useAlarm && carbs > 0 && timeOffset > 0)
|
||||
actions.add(rh.gs(R.string.alarminxmin, timeOffset).formatColor(rh, R.color.info))
|
||||
actions.add(rh.gs(R.string.alarminxmin, timeOffset).formatColor(context , rh, R.attr.infoColor))
|
||||
val duration = binding.duration.value.toInt()
|
||||
if (duration > 0)
|
||||
actions.add(rh.gs(R.string.duration) + ": " + duration + rh.gs(R.string.shorthour))
|
||||
if (carbsAfterConstraints > 0) {
|
||||
actions.add(rh.gs(R.string.carbs) + ": " + "<font color='" + rh.gc(R.color.carbs) + "'>" + rh.gs(R.string.format_carbs, carbsAfterConstraints) + "</font>")
|
||||
actions.add(rh.gs(R.string.carbs) + ": " + "<font color='" + rh.gac(context, R.attr.carbsColor) + "'>" + rh.gs(R.string.format_carbs, carbsAfterConstraints) + "</font>")
|
||||
if (carbsAfterConstraints != carbs)
|
||||
actions.add("<font color='" + rh.gc(R.color.warning) + "'>" + rh.gs(R.string.carbsconstraintapplied) + "</font>")
|
||||
actions.add("<font color='" + rh.gac(context, R.attr.warningColor) + "'>" + rh.gs(R.string.carbsconstraintapplied) + "</font>")
|
||||
}
|
||||
val notes = binding.notesLayout.notes.text.toString()
|
||||
if (notes.isNotEmpty())
|
||||
|
@ -377,4 +382,20 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,8 +165,8 @@ class CareDialog : DialogFragmentWithDate() {
|
|||
?: 0.0, 0.0, Constants.MAX_PROFILE_SWITCH_DURATION, 10.0, DecimalFormat("0"), false, binding.okcancel.ok)
|
||||
if (options == EventType.NOTE || options == EventType.QUESTION || options == EventType.ANNOUNCEMENT || options == EventType.EXERCISE)
|
||||
binding.notesLayout.root.visibility = View.VISIBLE // independent to preferences
|
||||
binding.bg.editText?.id?.let { binding.bgLabel.labelFor = it }
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.bgLabel.labelFor = binding.bg.editTextId
|
||||
binding.durationLabel.labelFor = binding.duration.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -22,7 +22,11 @@ import info.nightscout.androidaps.utils.HtmlHelper
|
|||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -36,11 +40,12 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var commandQueue: CommandQueue
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private var queryingProtection = false
|
||||
private var _binding: DialogExtendedbolusBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
|
@ -70,8 +75,8 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
val extendedMaxDuration = pumpDescription.extendedBolusMaxDuration
|
||||
binding.duration.setParams(savedInstanceState?.getDouble("duration")
|
||||
?: extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, DecimalFormat("0"), false, binding.okcancel.ok)
|
||||
binding.insulin.editText?.id?.let { binding.insulinLabel.labelFor = it }
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.insulinLabel.labelFor = binding.insulin.editTextId
|
||||
binding.durationLabel.labelFor = binding.duration.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -88,7 +93,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
actions.add(rh.gs(R.string.formatinsulinunits, insulinAfterConstraint))
|
||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
||||
if (abs(insulinAfterConstraint - insulin) > 0.01)
|
||||
actions.add(rh.gs(R.string.constraintapllied).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.constraintapllied).formatColor(context, rh, R.attr.warningColor))
|
||||
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.extended_bolus), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
|
@ -106,4 +111,20 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ import info.nightscout.androidaps.utils.HtmlHelper
|
|||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -44,13 +47,13 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private var queryingProtection = false
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private var _binding: DialogFillBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
|
@ -96,7 +99,7 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
} else {
|
||||
binding.fillPresetButton3.visibility = View.GONE
|
||||
}
|
||||
binding.fillInsulinamount.editText?.id?.let { binding.fillLabel.labelFor = it }
|
||||
binding.fillLabel.labelFor = binding.fillInsulinamount.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -113,16 +116,16 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
if (insulinAfterConstraints > 0) {
|
||||
actions.add(rh.gs(R.string.fillwarning))
|
||||
actions.add("")
|
||||
actions.add(rh.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, rh).formatColor(rh, R.color.colorInsulinButton))
|
||||
actions.add(rh.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, rh).formatColor(context, rh, R.attr.insulinButtonColor))
|
||||
if (abs(insulinAfterConstraints - insulin) > 0.01)
|
||||
actions.add(rh.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(context, rh, R.attr.warningColor))
|
||||
}
|
||||
val siteChange = binding.fillCatheterChange.isChecked
|
||||
if (siteChange)
|
||||
actions.add(rh.gs(R.string.record_pump_site_change).formatColor(rh, R.color.actionsConfirm))
|
||||
actions.add(rh.gs(R.string.record_pump_site_change).formatColor(context, rh, R.attr.actionsConfirmColor))
|
||||
val insulinChange = binding.fillCartridgeChange.isChecked
|
||||
if (insulinChange)
|
||||
actions.add(rh.gs(R.string.record_insulin_cartridge_change).formatColor(rh, R.color.actionsConfirm))
|
||||
actions.add(rh.gs(R.string.record_insulin_cartridge_change).formatColor(context, rh, R.attr.actionsConfirmColor))
|
||||
val notes: String = binding.notesLayout.notes.text.toString()
|
||||
if (notes.isNotEmpty())
|
||||
actions.add(rh.gs(R.string.notes_label) + ": " + notes)
|
||||
|
@ -196,4 +199,20 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ import info.nightscout.androidaps.queue.Callback
|
|||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.extensions.toSignedString
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.SafeParse
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
|
@ -52,6 +54,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var bolusTimer: BolusTimer
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -60,7 +63,12 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
private const val PLUS3_DEFAULT = 2.0
|
||||
}
|
||||
|
||||
private var queryingProtection = false
|
||||
private val disposable = CompositeDisposable()
|
||||
private var _binding: DialogInsulinBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val textWatcher: TextWatcher = object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
|
@ -71,12 +79,6 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
||||
}
|
||||
|
||||
private var _binding: DialogInsulinBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private fun validateInputs() {
|
||||
val maxInsulin = constraintChecker.getMaxBolusAllowed().value()
|
||||
if (abs(binding.time.value.toInt()) > 12 * 60) {
|
||||
|
@ -148,8 +150,8 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
binding.recordOnly.setOnCheckedChangeListener { _, isChecked: Boolean ->
|
||||
binding.timeLayout.visibility = isChecked.toVisibility()
|
||||
}
|
||||
binding.amount.editText?.id?.let { binding.insulinLabel.labelFor = it }
|
||||
binding.time.editText?.id?.let { binding.timeLabel.labelFor = it }
|
||||
binding.insulinLabel.labelFor = binding.amount.editTextId
|
||||
binding.timeLabel.labelFor = binding.time.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -170,16 +172,17 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
val eatingSoonChecked = binding.startEatingSoonTt.isChecked
|
||||
|
||||
if (insulinAfterConstraints > 0) {
|
||||
actions.add(rh.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, rh).formatColor(rh, R.color.bolus))
|
||||
actions.add(rh.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, rh).formatColor(context, rh, R.attr.bolusColor))
|
||||
if (recordOnlyChecked)
|
||||
actions.add(rh.gs(R.string.bolusrecordedonly).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.bolusrecordedonly).formatColor(context, rh, R.attr.warningColor))
|
||||
if (abs(insulinAfterConstraints - insulin) > pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints))
|
||||
actions.add(rh.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(context, rh, R.attr.warningColor))
|
||||
}
|
||||
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
||||
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
||||
if (eatingSoonChecked)
|
||||
actions.add(rh.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + rh.gs(R.string.format_mins, eatingSoonTTDuration) + ")").formatColor(rh, R.color.tempTargetConfirmation))
|
||||
actions.add(rh.gs(R.string.temptargetshort) + ": " + (DecimalFormatter.to1Decimal(eatingSoonTT) + " " + unitLabel + " (" + rh.gs(R.string.format_mins, eatingSoonTTDuration) + ")")
|
||||
.formatColor(context, rh, R.attr.tempTargetConfirmation))
|
||||
|
||||
val timeOffset = binding.time.value.toInt()
|
||||
val time = dateUtil.now() + T.mins(timeOffset.toLong()).msecs()
|
||||
|
@ -255,4 +258,20 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
|
@ -62,14 +64,15 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var objectivePlugin: ObjectivesPlugin
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private var queryingProtection = false
|
||||
private var showOkCancel: Boolean = true
|
||||
private var _binding: DialogLoopBinding? = null
|
||||
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
private lateinit var refreshDialog: Runnable
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
val disposable = CompositeDisposable()
|
||||
|
@ -437,4 +440,20 @@ class LoopDialog : DaggerDialogFragment() {
|
|||
aapsLogger.debug(e.localizedMessage ?: e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
|
@ -30,7 +31,10 @@ import info.nightscout.androidaps.utils.DefaultValueHelper
|
|||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -51,15 +55,15 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var hardLimits: HardLimits
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var ctx: Context
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private var profileIndex: Int? = null
|
||||
|
||||
private var queryingProtection = false
|
||||
private var profileName: String? = null
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private var _binding: DialogProfileswitchBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val textWatcher: TextWatcher = object : TextWatcher {
|
||||
|
@ -86,7 +90,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
): View {
|
||||
onCreateViewGeneral()
|
||||
arguments?.let { bundle ->
|
||||
profileIndex = bundle.getInt("profileIndex", 0)
|
||||
profileName = bundle.getString("profileName", null)
|
||||
}
|
||||
_binding = DialogProfileswitchBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
@ -112,8 +116,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
|
||||
// profile
|
||||
context?.let { context ->
|
||||
val profileStore = activePlugin.activeProfileSource.profile
|
||||
?: return
|
||||
val profileStore = activePlugin.activeProfileSource.profile ?: return
|
||||
val profileListToCheck = profileStore.getProfileList()
|
||||
val profileList = ArrayList<CharSequence>()
|
||||
for (profileName in profileListToCheck) {
|
||||
|
@ -125,15 +128,16 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
dismiss()
|
||||
return
|
||||
}
|
||||
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
|
||||
binding.profile.adapter = adapter
|
||||
binding.profileList.setAdapter(ArrayAdapter(context, R.layout.spinner_centered, profileList))
|
||||
// set selected to actual profile
|
||||
if (profileIndex != null)
|
||||
binding.profile.setSelection(profileIndex as Int)
|
||||
else
|
||||
if (profileName != null)
|
||||
binding.profileList.setText(profileName, false)
|
||||
else {
|
||||
binding.profileList.setText(profileList[0], false)
|
||||
for (p in profileList.indices)
|
||||
if (profileList[p] == profileFunction.getOriginalProfileName())
|
||||
binding.profile.setSelection(p)
|
||||
binding.profileList.setText(profileList[p], false)
|
||||
}
|
||||
}
|
||||
|
||||
profileFunction.getProfile()?.let { profile ->
|
||||
|
@ -148,9 +152,9 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
}
|
||||
binding.ttLayout.visibility = View.GONE
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.percentage.editText?.id?.let { binding.percentageLabel.labelFor = it }
|
||||
binding.timeshift.editText?.id?.let { binding.timeshiftLabel.labelFor = it }
|
||||
binding.durationLabel.labelFor = binding.duration.editTextId
|
||||
binding.percentageLabel.labelFor = binding.percentage.editTextId
|
||||
binding.timeshiftLabel.labelFor = binding.timeshift.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -168,7 +172,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
val duration = binding.duration.value.toInt()
|
||||
if (duration > 0L)
|
||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, duration))
|
||||
val profileName = binding.profile.selectedItem.toString()
|
||||
val profileName = binding.profileList.text.toString()
|
||||
actions.add(rh.gs(R.string.profile) + ": " + profileName)
|
||||
val percent = binding.percentage.value.toInt()
|
||||
if (percent != 100)
|
||||
|
@ -245,4 +249,20 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,11 @@ import info.nightscout.androidaps.utils.HtmlHelper
|
|||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -35,13 +39,13 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var commandQueue: CommandQueue
|
||||
@Inject lateinit var ctx: Context
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private var queryingProtection = false
|
||||
private var isPercentPump = true
|
||||
|
||||
private var _binding: DialogTempbasalBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
|
@ -51,8 +55,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
savedInstanceState.putDouble("basalAbsoluteInput", binding.basalAbsoluteInput.value)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
onCreateViewGeneral()
|
||||
_binding = DialogTempbasalBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
@ -86,9 +89,9 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
binding.percentLayout.visibility = View.GONE
|
||||
binding.absoluteLayout.visibility = View.VISIBLE
|
||||
}
|
||||
binding.basalPercentInput.editText?.id?.let { binding.basalPercentLabel.labelFor = it }
|
||||
binding.basalAbsoluteInput.editText?.id?.let { binding.basalAbsoluteLabel.labelFor = it }
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.basalPercentLabel.labelFor = binding.basalPercentInput.editTextId
|
||||
binding.basalAbsoluteLabel.labelFor = binding.basalAbsoluteInput.editTextId
|
||||
binding.durationLabel.labelFor = binding.duration.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -115,7 +118,7 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
actions.add(rh.gs(R.string.tempbasal_label) + ": " + rh.gs(R.string.pump_basebasalrate, absolute))
|
||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
||||
if (abs(absolute - basalAbsoluteInput) > 0.01)
|
||||
actions.add(rh.gs(R.string.constraintapllied).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.constraintapllied).formatColor(context, rh, R.attr.warningColor))
|
||||
}
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.tempbasal_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
|
||||
|
@ -141,4 +144,20 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -26,7 +27,10 @@ import info.nightscout.androidaps.logging.UserEntryLogger
|
|||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
import info.nightscout.androidaps.utils.HtmlHelper
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -43,15 +47,16 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var ctx: Context
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private lateinit var reasonList: List<String>
|
||||
|
||||
private var queryingProtection = false
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private var _binding: DialogTemptargetBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
|
@ -60,8 +65,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
savedInstanceState.putDouble("tempTarget", binding.temptarget.value)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
onCreateViewGeneral()
|
||||
_binding = DialogTemptargetBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
@ -100,10 +104,9 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
rh.gs(R.string.activity),
|
||||
rh.gs(R.string.hypo)
|
||||
)
|
||||
val adapterReason = ArrayAdapter(context, R.layout.spinner_centered, reasonList)
|
||||
binding.reason.adapter = adapterReason
|
||||
binding.reasonList.setAdapter(ArrayAdapter(context, R.layout.spinner_centered, reasonList))
|
||||
|
||||
binding.targetCancel.setOnClickListener { shortClick(it) }
|
||||
binding.targetCancel.setOnClickListener { binding.duration.value = 0.0; shortClick(it) }
|
||||
binding.eatingSoon.setOnClickListener { shortClick(it) }
|
||||
binding.activity.setOnClickListener { shortClick(it) }
|
||||
binding.hypo.setOnClickListener { shortClick(it) }
|
||||
|
@ -120,8 +123,8 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
longClick(it)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
binding.duration.editText?.id?.let { binding.durationLabel.labelFor = it }
|
||||
binding.temptarget.editText?.id?.let { binding.temptargetLabel.labelFor = it }
|
||||
binding.durationLabel.labelFor = binding.duration.editTextId
|
||||
binding.temptargetLabel.labelFor = binding.temptarget.editTextId
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,23 +138,19 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
R.id.eating_soon -> {
|
||||
binding.temptarget.value = defaultValueHelper.determineEatingSoonTT()
|
||||
binding.duration.value = defaultValueHelper.determineEatingSoonTTDuration().toDouble()
|
||||
binding.reason.setSelection(reasonList.indexOf(rh.gs(R.string.eatingsoon)))
|
||||
binding.reasonList.setText(rh.gs(R.string.eatingsoon), false)
|
||||
}
|
||||
|
||||
R.id.activity -> {
|
||||
binding.temptarget.value = defaultValueHelper.determineActivityTT()
|
||||
binding.duration.value = defaultValueHelper.determineActivityTTDuration().toDouble()
|
||||
binding.reason.setSelection(reasonList.indexOf(rh.gs(R.string.activity)))
|
||||
binding.reasonList.setText(rh.gs(R.string.activity), false)
|
||||
}
|
||||
|
||||
R.id.hypo -> {
|
||||
binding.temptarget.value = defaultValueHelper.determineHypoTT()
|
||||
binding.duration.value = defaultValueHelper.determineHypoTTDuration().toDouble()
|
||||
binding.reason.setSelection(reasonList.indexOf(rh.gs(R.string.hypo)))
|
||||
}
|
||||
|
||||
R.id.cancel -> {
|
||||
binding.duration.value = 0.0
|
||||
binding.reasonList.setText(rh.gs(R.string.hypo), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +164,7 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
override fun submit(): Boolean {
|
||||
if (_binding == null) return false
|
||||
val actions: LinkedList<String> = LinkedList()
|
||||
var reason = binding.reason.selectedItem?.toString() ?: return false
|
||||
var reason = binding.reasonList.text.toString()
|
||||
val unitResId = if (profileFunction.getUnits() == GlucoseUnit.MGDL) R.string.mgdl else R.string.mmol
|
||||
val target = binding.temptarget.value
|
||||
val duration = binding.duration.value.toInt()
|
||||
|
@ -222,4 +221,20 @@ class TempTargetDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import info.nightscout.shared.SafeParse
|
|||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -48,8 +50,14 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private var queryingProtection = false
|
||||
private val disposable = CompositeDisposable()
|
||||
private var _binding: DialogTreatmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val textWatcher: TextWatcher = object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {}
|
||||
|
@ -72,12 +80,6 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
}
|
||||
|
||||
private var _binding: DialogTreatmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
super.onSaveInstanceState(savedInstanceState)
|
||||
savedInstanceState.putDouble("carbs", binding.carbs.value)
|
||||
|
@ -106,8 +108,8 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
binding.insulin.setParams(savedInstanceState?.getDouble("insulin")
|
||||
?: 0.0, 0.0, maxInsulin, pumpDescription.bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
|
||||
binding.recordOnlyLayout.visibility = View.GONE
|
||||
binding.insulin.editText?.id?.let { binding.insulinLabel.labelFor = it }
|
||||
binding.carbs.editText?.id?.let { binding.carbsLabel.labelFor = it }
|
||||
binding.insulinLabel.labelFor = binding.insulin.editTextId
|
||||
binding.carbsLabel.labelFor = binding.carbs.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -126,16 +128,16 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
||||
|
||||
if (insulinAfterConstraints > 0) {
|
||||
actions.add(rh.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, rh).formatColor(rh, R.color.bolus))
|
||||
actions.add(rh.gs(R.string.bolus) + ": " + DecimalFormatter.toPumpSupportedBolus(insulinAfterConstraints, activePlugin.activePump, rh).formatColor(context, rh, R.attr.bolusColor))
|
||||
if (recordOnlyChecked)
|
||||
actions.add(rh.gs(R.string.bolusrecordedonly).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.bolusrecordedonly).formatColor(context, rh, R.attr.warningColor))
|
||||
if (abs(insulinAfterConstraints - insulin) > pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints))
|
||||
actions.add(rh.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.bolusconstraintappliedwarn, insulin, insulinAfterConstraints).formatColor(context, rh, R.attr.warningColor))
|
||||
}
|
||||
if (carbsAfterConstraints > 0) {
|
||||
actions.add(rh.gs(R.string.carbs) + ": " + rh.gs(R.string.format_carbs, carbsAfterConstraints).formatColor(rh, R.color.carbs))
|
||||
actions.add(rh.gs(R.string.carbs) + ": " + rh.gs(R.string.format_carbs, carbsAfterConstraints).formatColor(context, rh, R.attr.carbsColor))
|
||||
if (carbsAfterConstraints != carbs)
|
||||
actions.add(rh.gs(R.string.carbsconstraintapplied).formatColor(rh, R.color.warning))
|
||||
actions.add(rh.gs(R.string.carbsconstraintapplied).formatColor(context, rh, R.attr.warningColor))
|
||||
}
|
||||
if (insulinAfterConstraints > 0 || carbsAfterConstraints > 0) {
|
||||
activity?.let { activity ->
|
||||
|
@ -201,4 +203,20 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package info.nightscout.androidaps.dialogs
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.*
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import android.widget.AdapterView
|
||||
import android.widget.AdapterView.OnItemSelectedListener
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.CompoundButton
|
||||
import androidx.fragment.app.FragmentManager
|
||||
|
@ -20,22 +24,24 @@ import info.nightscout.androidaps.database.ValueWrapper
|
|||
import info.nightscout.androidaps.databinding.DialogWizardBinding
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.extensions.formatColor
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.extensions.valueToUnits
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
||||
|
@ -55,16 +61,22 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
|
||||
private var queryingProtection = false
|
||||
private var wizard: BolusWizard? = null
|
||||
private var calculatedPercentage = 100.0
|
||||
private var calculatedCorrection = 0.0
|
||||
private var correctionPercent = false
|
||||
private var carbsPassedIntoWizard = 0.0
|
||||
private var notesPassedIntoWizard = ""
|
||||
private var okClicked: Boolean = false // one shot guards
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private var bolusStep = 0.0
|
||||
private var _binding: DialogWizardBinding? = null
|
||||
|
||||
//one shot guards
|
||||
private var okClicked: Boolean = false
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val textWatcher = object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {}
|
||||
|
@ -83,15 +95,6 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private var bolusStep = 0.0
|
||||
|
||||
private var _binding: DialogWizardBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
|
@ -106,10 +109,9 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
savedInstanceState.putDouble("carb_time_input", binding.carbTimeInput.value)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
this.arguments?.let { bundle ->
|
||||
carbsPassedIntoWizard = bundle.getInt("carbs_input").toDouble()
|
||||
carbsPassedIntoWizard = bundle.getDouble("carbs_input")
|
||||
notesPassedIntoWizard = bundle.getString("notes_input").toString()
|
||||
}
|
||||
|
||||
|
@ -128,7 +130,7 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
val useSuperBolus = sp.getBoolean(R.string.key_usesuperbolus, false)
|
||||
binding.sbCheckbox.visibility = useSuperBolus.toVisibility()
|
||||
binding.superBolusRow.visibility = useSuperBolus.toVisibility()
|
||||
binding.notesLayout.visibility = sp.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
|
||||
binding.notesLayout.root.visibility = sp.getBoolean(R.string.key_show_notes_entry_dialogs, false).toVisibility()
|
||||
|
||||
val maxCarbs = constraintChecker.getMaxCarbsAllowed().value()
|
||||
val maxCorrection = constraintChecker.getMaxBolusAllowed().value()
|
||||
|
@ -137,14 +139,18 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
if (profileFunction.getUnits() == GlucoseUnit.MGDL) {
|
||||
binding.bgInput.setParams(
|
||||
savedInstanceState?.getDouble("bg_input")
|
||||
?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, timeTextWatcher)
|
||||
?: 0.0, 0.0, 500.0, 1.0, DecimalFormat("0"), false, binding.okcancel.ok, timeTextWatcher
|
||||
)
|
||||
} else {
|
||||
binding.bgInput.setParams(
|
||||
savedInstanceState?.getDouble("bg_input")
|
||||
?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.okcancel.ok, textWatcher)
|
||||
?: 0.0, 0.0, 30.0, 0.1, DecimalFormat("0.0"), false, binding.okcancel.ok, textWatcher
|
||||
)
|
||||
}
|
||||
binding.carbsInput.setParams(savedInstanceState?.getDouble("carbs_input")
|
||||
?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher)
|
||||
binding.carbsInput.setParams(
|
||||
savedInstanceState?.getDouble("carbs_input")
|
||||
?: 0.0, 0.0, maxCarbs.toDouble(), 1.0, DecimalFormat("0"), false, binding.okcancel.ok, textWatcher
|
||||
)
|
||||
|
||||
if (correctionPercent) {
|
||||
calculatedPercentage = sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble()
|
||||
|
@ -154,11 +160,14 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
} else {
|
||||
binding.correctionInput.setParams(
|
||||
savedInstanceState?.getDouble("correction_input")
|
||||
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher)
|
||||
?: 0.0, -maxCorrection, maxCorrection, bolusStep, DecimalFormatter.pumpSupportedBolusFormat(activePlugin.activePump), false, binding.okcancel.ok, textWatcher
|
||||
)
|
||||
binding.correctionUnit.text = rh.gs(R.string.insulin_unit_shortname)
|
||||
}
|
||||
binding.carbTimeInput.setParams(savedInstanceState?.getDouble("carb_time_input")
|
||||
?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, binding.okcancel.ok, timeTextWatcher)
|
||||
binding.carbTimeInput.setParams(
|
||||
savedInstanceState?.getDouble("carb_time_input")
|
||||
?: 0.0, -60.0, 60.0, 5.0, DecimalFormat("0"), false, binding.okcancel.ok, timeTextWatcher
|
||||
)
|
||||
initDialog()
|
||||
calculatedPercentage = sp.getInt(R.string.key_boluswizard_percentage, 100).toDouble()
|
||||
binding.percentUsed.text = rh.gs(R.string.format_percent, sp.getInt(R.string.key_boluswizard_percentage, 100))
|
||||
|
@ -209,7 +218,7 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
|
||||
processEnabledIcons()
|
||||
|
||||
binding.correctionPercent.setOnCheckedChangeListener {_, isChecked ->
|
||||
binding.correctionPercent.setOnCheckedChangeListener { _, isChecked ->
|
||||
run {
|
||||
sp.putBoolean(rh.gs(R.string.key_wizard_correction_percent), isChecked)
|
||||
binding.correctionUnit.text = if (isChecked) "%" else rh.gs(R.string.insulin_unit_shortname)
|
||||
|
@ -228,35 +237,21 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
binding.correctionInput.value = if (correctionPercent) calculatedPercentage else Round.roundTo(calculatedCorrection, bolusStep)
|
||||
}
|
||||
}
|
||||
// profile spinner
|
||||
binding.profile.onItemSelectedListener = object : OnItemSelectedListener {
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||
ToastUtils.showToastInUiThread(ctx, rh.gs(R.string.noprofileset))
|
||||
binding.okcancel.ok.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
calculateInsulin()
|
||||
binding.okcancel.ok.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
// profile
|
||||
binding.profileList.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, _ -> calculateInsulin() }
|
||||
// bus
|
||||
disposable.add(rxBus
|
||||
disposable += rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({
|
||||
activity?.runOnUiThread { calculateInsulin() }
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
|
||||
.subscribe({ calculateInsulin() }, fabricPrivacy::logException)
|
||||
setA11yLabels()
|
||||
}
|
||||
|
||||
private fun setA11yLabels() {
|
||||
binding.bgInput.editText?.id?.let { binding.bgInputLabel.labelFor = it }
|
||||
binding.carbsInput.editText?.id?.let { binding.carbsInputLabel.labelFor = it }
|
||||
binding.correctionInput.editText?.id?.let { binding.correctionInputLabel.labelFor = it }
|
||||
binding.carbTimeInput.editText?.id?.let { binding.carbTimeInputLabel.labelFor = it }
|
||||
binding.bgInputLabel.labelFor = binding.bgInput.editTextId
|
||||
binding.carbsInputLabel.labelFor = binding.carbsInput.editTextId
|
||||
binding.correctionInputLabel.labelFor = binding.correctionInput.editTextId
|
||||
binding.carbTimeInputLabel.labelFor = binding.carbTimeInput.editTextId
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -307,6 +302,7 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
binding.trendCheckboxIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
|
||||
binding.iobCheckboxIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
|
||||
binding.cobCheckboxIcon.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
|
||||
binding.checkboxRow.visibility = binding.calculationCheckbox.isChecked.not().toVisibility()
|
||||
}
|
||||
|
||||
private fun saveCheckedStates() {
|
||||
|
@ -318,7 +314,7 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
private fun loadCheckedStates() {
|
||||
binding.bgTrendCheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_trend_bg, false)
|
||||
binding.cobCheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false)
|
||||
correctionPercent = sp.getBoolean(R.string.key_wizard_correction_percent,false)
|
||||
correctionPercent = sp.getBoolean(R.string.key_wizard_correction_percent, false)
|
||||
binding.correctionPercent.isChecked = correctionPercent
|
||||
}
|
||||
|
||||
|
@ -327,11 +323,11 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
else DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL)
|
||||
|
||||
private fun initDialog() {
|
||||
if(carbsPassedIntoWizard != 0.0) {
|
||||
if (carbsPassedIntoWizard != 0.0) {
|
||||
binding.carbsInput.value = carbsPassedIntoWizard
|
||||
}
|
||||
if(notesPassedIntoWizard.isNotBlank()) {
|
||||
binding.notes.setText(notesPassedIntoWizard)
|
||||
if (notesPassedIntoWizard.isNotBlank()) {
|
||||
binding.notesLayout.notes.setText(notesPassedIntoWizard)
|
||||
}
|
||||
val profile = profileFunction.getProfile()
|
||||
val profileStore = activePlugin.activeProfileSource.profile
|
||||
|
@ -345,9 +341,9 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
val profileList: ArrayList<CharSequence> = profileStore.getProfileList()
|
||||
profileList.add(0, rh.gs(R.string.active))
|
||||
context?.let { context ->
|
||||
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
|
||||
binding.profile.adapter = adapter
|
||||
} ?: return
|
||||
binding.profileList.setAdapter(ArrayAdapter(context, R.layout.spinner_centered, profileList))
|
||||
binding.profileList.setText(profileList[0], false)
|
||||
}
|
||||
|
||||
val units = profileFunction.getUnits()
|
||||
binding.bgUnits.text = units.asText
|
||||
|
@ -370,11 +366,10 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
binding.percentUsed.visibility = (sp.getInt(R.string.key_boluswizard_percentage, 100) != 100 || correctionPercent).toVisibility()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun calculateInsulin() {
|
||||
val profileStore = activePlugin.activeProfileSource.profile
|
||||
if (binding.profile.selectedItem == null || profileStore == null)
|
||||
return // not initialized yet
|
||||
var profileName = binding.profile.selectedItem.toString()
|
||||
val profileStore = activePlugin.activeProfileSource.profile ?: return // not initialized yet
|
||||
var profileName = binding.profileList.text.toString()
|
||||
val specificProfile: Profile?
|
||||
if (profileName == rh.gs(R.string.active)) {
|
||||
specificProfile = profileFunction.getProfile()
|
||||
|
@ -396,7 +391,7 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
} else
|
||||
0.0
|
||||
val percentageCorrection = if (usePercentage) {
|
||||
if (Round.roundTo(calculatedPercentage,1.0) == SafeParse.stringToDouble(binding.correctionInput.text))
|
||||
if (Round.roundTo(calculatedPercentage, 1.0) == SafeParse.stringToDouble(binding.correctionInput.text))
|
||||
calculatedPercentage
|
||||
else
|
||||
SafeParse.stringToDouble(binding.correctionInput.text)
|
||||
|
@ -422,7 +417,8 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
|
||||
val carbTime = SafeParse.stringToInt(binding.carbTimeInput.text)
|
||||
|
||||
wizard = BolusWizard(injector).doCalc(specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, sp.getInt(R.string.key_boluswizard_percentage, 100),
|
||||
wizard = BolusWizard(injector).doCalc(
|
||||
specificProfile, profileName, tempTarget, carbsAfterConstraint, cob, bg, correction, sp.getInt(R.string.key_boluswizard_percentage, 100),
|
||||
binding.bgCheckbox.isChecked,
|
||||
binding.cobCheckbox.isChecked,
|
||||
binding.iobCheckbox.isChecked,
|
||||
|
@ -431,17 +427,17 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
binding.ttCheckbox.isChecked,
|
||||
binding.bgTrendCheckbox.isChecked,
|
||||
binding.alarm.isChecked,
|
||||
binding.notes.text.toString(),
|
||||
binding.notesLayout.notes.text.toString(),
|
||||
carbTime,
|
||||
usePercentage = usePercentage,
|
||||
totalPercentage = percentageCorrection
|
||||
)
|
||||
|
||||
wizard?.let { wizard ->
|
||||
binding.bg.text = String.format(rh.gs(R.string.format_bg_isf), valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits().asText), wizard.sens)
|
||||
binding.bg.text = rh.gs(R.string.format_bg_isf, valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits().asText), wizard.sens)
|
||||
binding.bgInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromBG)
|
||||
|
||||
binding.carbs.text = String.format(rh.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)
|
||||
binding.carbs.text = rh.gs(R.string.format_carbs_ic, carbs.toDouble(), wizard.ic)
|
||||
binding.carbsInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromCarbs)
|
||||
|
||||
binding.iobInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromBolusIOB + wizard.insulinFromBasalIOB)
|
||||
|
@ -464,7 +460,7 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
|
||||
// COB
|
||||
if (binding.cobCheckbox.isChecked) {
|
||||
binding.cob.text = String.format(rh.gs(R.string.format_cob_ic), cob, wizard.ic)
|
||||
binding.cob.text = rh.gs(R.string.format_cob_ic, cob, wizard.ic)
|
||||
binding.cobInsulin.text = rh.gs(R.string.formatinsulinunits, wizard.insulinFromCOB)
|
||||
} else {
|
||||
binding.cob.text = ""
|
||||
|
@ -472,12 +468,12 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
}
|
||||
|
||||
if (wizard.calculatedTotalInsulin > 0.0 || carbsAfterConstraint > 0.0) {
|
||||
val insulinText = if (wizard.calculatedTotalInsulin > 0.0) rh.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin).formatColor(rh, R.color.bolus) else ""
|
||||
val carbsText = if (carbsAfterConstraint > 0.0) rh.gs(R.string.format_carbs, carbsAfterConstraint).formatColor(rh, R.color.carbs) else ""
|
||||
val insulinText = if (wizard.calculatedTotalInsulin > 0.0) rh.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin).formatColor(context, rh, R.attr.bolusColor) else ""
|
||||
val carbsText = if (carbsAfterConstraint > 0.0) rh.gs(R.string.format_carbs, carbsAfterConstraint).formatColor(context, rh, R.attr.carbsColor) else ""
|
||||
binding.total.text = HtmlHelper.fromHtml(rh.gs(R.string.result_insulin_carbs, insulinText, carbsText))
|
||||
binding.okcancel.ok.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.total.text = HtmlHelper.fromHtml(rh.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()).formatColor(rh, R.color.carbs))
|
||||
binding.total.text = HtmlHelper.fromHtml(rh.gs(R.string.missing_carbs, wizard.carbsEquivalent.toInt()).formatColor(context, rh, R.attr.carbsColor))
|
||||
binding.okcancel.ok.visibility = View.INVISIBLE
|
||||
}
|
||||
binding.percentUsed.text = rh.gs(R.string.format_percent, wizard.percentageCorrection)
|
||||
|
@ -497,4 +493,20 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
aapsLogger.debug(e.localizedMessage ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if(!queryingProtection) {
|
||||
queryingProtection = true
|
||||
activity?.let { activity ->
|
||||
val cancelFail = {
|
||||
queryingProtection = false
|
||||
aapsLogger.debug(LTag.APS, "Dialog canceled on resume protection: ${this.javaClass.name}")
|
||||
ToastUtils.showToastInUiThread(ctx, R.string.dialog_canceled)
|
||||
dismiss()
|
||||
}
|
||||
protectionCheck.queryProtection(activity, BOLUS, { queryingProtection = false }, cancelFail, cancelFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
class EventReloadProfileSwitchData : Event()
|
|
@ -1,3 +0,0 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
class EventTreatmentUpdateGui : EventUpdateGui()
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.aps.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventLoopInvoked : Event()
|
|
@ -10,11 +10,13 @@ import android.content.Intent
|
|||
import android.os.SystemClock
|
||||
import androidx.core.app.NotificationCompat
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.*
|
||||
import info.nightscout.androidaps.BuildConfig
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.MainActivity
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
|
@ -25,13 +27,13 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit
|
|||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventNewBG
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.extensions.buildDeviceStatus
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.convertedToPercent
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.interfaces.Loop.LastRun
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopSetLastRunGui
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
|
||||
|
@ -51,13 +53,10 @@ import info.nightscout.androidaps.utils.DateUtil
|
|||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.extensions.buildDeviceStatus
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.convertedToPercent
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -88,20 +87,21 @@ class LoopPlugin @Inject constructor(
|
|||
private val uel: UserEntryLogger,
|
||||
private val repository: AppRepository,
|
||||
private val runningConfiguration: RunningConfiguration
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.LOOP)
|
||||
.fragmentClass(LoopFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_loop_closed_white)
|
||||
.pluginName(R.string.loop)
|
||||
.shortName(R.string.loop_shortname)
|
||||
.preferencesId(R.xml.pref_loop)
|
||||
.enableByDefault(config.APS)
|
||||
.description(R.string.description_loop),
|
||||
) : PluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.LOOP)
|
||||
.fragmentClass(LoopFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_loop_closed_white)
|
||||
.pluginName(R.string.loop)
|
||||
.shortName(R.string.loop_shortname)
|
||||
.preferencesId(R.xml.pref_loop)
|
||||
.enableByDefault(config.APS)
|
||||
.description(R.string.description_loop),
|
||||
aapsLogger, rh, injector
|
||||
), Loop {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
private var lastBgTriggeredRun: Long = 0
|
||||
override var lastBgTriggeredRun: Long = 0
|
||||
private var carbsSuggestionsSuspendedUntil: Long = 0
|
||||
private var prevCarbsreq = 0
|
||||
override var lastRun: LastRun? = null
|
||||
|
@ -109,39 +109,19 @@ class LoopPlugin @Inject constructor(
|
|||
override fun onStart() {
|
||||
createNotificationChannel()
|
||||
super.onStart()
|
||||
disposable.add(rxBus
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempTargetChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ invoke("EventTempTargetChange", true) }, fabricPrivacy::logException)
|
||||
)
|
||||
/*
|
||||
This method is triggered once autosens calculation has completed, so the LoopPlugin
|
||||
has current data to work with. However, autosens calculation can be triggered by multiple
|
||||
sources and currently only a new BG should trigger a loop run. Hence we return early if
|
||||
the event causing the calculation is not EventNewBg.
|
||||
<p>
|
||||
*/
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventAutosensCalculationFinished ->
|
||||
// Autosens calculation not triggered by a new BG
|
||||
if (event.cause !is EventNewBG) return@subscribe
|
||||
val glucoseValue = iobCobCalculator.ads.actualBg() ?: return@subscribe
|
||||
// BG outdated
|
||||
// already looped with that value
|
||||
if (glucoseValue.timestamp <= lastBgTriggeredRun) return@subscribe
|
||||
lastBgTriggeredRun = glucoseValue.timestamp
|
||||
invoke("AutosenseCalculation for $glucoseValue", true)
|
||||
}, fabricPrivacy::logException)
|
||||
)
|
||||
}
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
@SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID,
|
||||
@SuppressLint("WrongConstant") val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
NotificationManager.IMPORTANCE_HIGH)
|
||||
CHANNEL_ID,
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
)
|
||||
mNotificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
|
@ -255,7 +235,7 @@ class LoopPlugin @Inject constructor(
|
|||
if (apsResult == null) {
|
||||
rxBus.send(EventLoopSetLastRunGui(rh.gs(R.string.noapsselected)))
|
||||
return
|
||||
} else rxBus.send(EventLoopInvoked())
|
||||
}
|
||||
|
||||
if (!isEmptyQueue()) {
|
||||
aapsLogger.debug(LTag.APS, rh.gs(R.string.pumpbusy))
|
||||
|
@ -296,9 +276,11 @@ class LoopPlugin @Inject constructor(
|
|||
lastRun.lastTBRRequest = 0
|
||||
lastRun.lastSMBEnact = 0
|
||||
lastRun.lastSMBRequest = 0
|
||||
buildDeviceStatus(dateUtil, this, iobCobCalculator, profileFunction,
|
||||
buildDeviceStatus(
|
||||
dateUtil, this, iobCobCalculator, profileFunction,
|
||||
activePlugin.activePump, receiverStatusStore, runningConfiguration,
|
||||
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also {
|
||||
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION
|
||||
)?.also {
|
||||
repository.insert(it)
|
||||
}
|
||||
|
||||
|
@ -316,7 +298,11 @@ class LoopPlugin @Inject constructor(
|
|||
if (closedLoopEnabled.value()) {
|
||||
if (allowNotification) {
|
||||
if (resultAfterConstraints.isCarbsRequired
|
||||
&& resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)) {
|
||||
&& resultAfterConstraints.carbsReq >= sp.getInt(
|
||||
R.string.key_smb_enable_carbs_suggestions_threshold,
|
||||
0
|
||||
) && carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimeThreshold(-15)
|
||||
) {
|
||||
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
val carbReqLocal = Notification(Notification.CARBS_REQUIRED, resultAfterConstraints.carbsRequiredText, Notification.NORMAL)
|
||||
rxBus.send(EventNewNotification(carbReqLocal))
|
||||
|
@ -353,9 +339,11 @@ class LoopPlugin @Inject constructor(
|
|||
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(Constants.notificationID, builder.build())
|
||||
uel.log(Action.CAREPORTAL, Sources.Loop, rh.gs(R.string.carbsreq, resultAfterConstraints.carbsReq, resultAfterConstraints.carbsReqWithin),
|
||||
ValueWithUnit.Gram(resultAfterConstraints.carbsReq),
|
||||
ValueWithUnit.Minute(resultAfterConstraints.carbsReqWithin))
|
||||
uel.log(
|
||||
Action.CAREPORTAL, Sources.Loop, rh.gs(R.string.carbsreq, resultAfterConstraints.carbsReq, resultAfterConstraints.carbsReqWithin),
|
||||
ValueWithUnit.Gram(resultAfterConstraints.carbsReq),
|
||||
ValueWithUnit.Minute(resultAfterConstraints.carbsReqWithin)
|
||||
)
|
||||
rxBus.send(EventNewOpenLoopNotification())
|
||||
|
||||
//only send to wear if Native notifications are turned off
|
||||
|
@ -373,7 +361,8 @@ class LoopPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
if (resultAfterConstraints.isChangeRequested
|
||||
&& !commandQueue.bolusInQueue()) {
|
||||
&& !commandQueue.bolusInQueue()
|
||||
) {
|
||||
val waiting = PumpEnactResult(injector)
|
||||
waiting.queued = true
|
||||
if (resultAfterConstraints.tempBasalRequested) lastRun.tbrSetByPump = waiting
|
||||
|
@ -486,9 +475,11 @@ class LoopPlugin @Inject constructor(
|
|||
lastRun.lastTBRRequest = lastRun.lastAPSRun
|
||||
lastRun.lastTBREnact = dateUtil.now()
|
||||
lastRun.lastOpenModeAccept = dateUtil.now()
|
||||
buildDeviceStatus(dateUtil, this@LoopPlugin, iobCobCalculator, profileFunction,
|
||||
buildDeviceStatus(
|
||||
dateUtil, this@LoopPlugin, iobCobCalculator, profileFunction,
|
||||
activePlugin.activePump, receiverStatusStore, runningConfiguration,
|
||||
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION)?.also {
|
||||
BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION
|
||||
)?.also {
|
||||
repository.insert(it)
|
||||
}
|
||||
sp.incInt(R.string.key_ObjectivesmanualEnacts)
|
||||
|
@ -531,8 +522,10 @@ class LoopPlugin @Inject constructor(
|
|||
commandQueue.cancelTempBasal(false, callback)
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).absolute(request.rate).duration(0)
|
||||
.enacted(false).success(true).comment(R.string.basal_set_correctly))?.run()
|
||||
callback?.result(
|
||||
PumpEnactResult(injector).absolute(request.rate).duration(0)
|
||||
.enacted(false).success(true).comment(R.string.basal_set_correctly)
|
||||
)?.run()
|
||||
}
|
||||
} else if (request.usePercent && allowPercentage()) {
|
||||
if (request.percent == 100 && request.duration == 0) {
|
||||
|
@ -542,32 +535,52 @@ class LoopPlugin @Inject constructor(
|
|||
commandQueue.cancelTempBasal(false, callback)
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).percent(request.percent).duration(0)
|
||||
.enacted(false).success(true).comment(R.string.basal_set_correctly))?.run()
|
||||
callback?.result(
|
||||
PumpEnactResult(injector).percent(request.percent).duration(0)
|
||||
.enacted(false).success(true).comment(R.string.basal_set_correctly)
|
||||
)?.run()
|
||||
}
|
||||
} else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.convertedToPercent(now, profile)) {
|
||||
} else if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && request.percent == activeTemp.convertedToPercent(
|
||||
now,
|
||||
profile
|
||||
)
|
||||
) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).percent(request.percent)
|
||||
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||
.comment(R.string.let_temp_basal_run))?.run()
|
||||
callback?.result(
|
||||
PumpEnactResult(injector).percent(request.percent)
|
||||
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||
.comment(R.string.let_temp_basal_run)
|
||||
)?.run()
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: tempBasalPercent()")
|
||||
uel.log(Action.TEMP_BASAL, Sources.Loop,
|
||||
uel.log(
|
||||
Action.TEMP_BASAL, Sources.Loop,
|
||||
ValueWithUnit.Percent(request.percent),
|
||||
ValueWithUnit.Minute(request.duration))
|
||||
ValueWithUnit.Minute(request.duration)
|
||||
)
|
||||
commandQueue.tempBasalPercent(request.percent, request.duration, false, profile, PumpSync.TemporaryBasalType.NORMAL, callback)
|
||||
}
|
||||
} else {
|
||||
if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(request.rate - activeTemp.convertedToAbsolute(now, profile)) < pump.pumpDescription.basalStep) {
|
||||
if (activeTemp != null && activeTemp.plannedRemainingMinutes > 5 && request.duration - activeTemp.plannedRemainingMinutes < 30 && abs(
|
||||
request.rate - activeTemp.convertedToAbsolute(
|
||||
now,
|
||||
profile
|
||||
)
|
||||
) < pump.pumpDescription.basalStep
|
||||
) {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: Temp basal set correctly")
|
||||
callback?.result(PumpEnactResult(injector).absolute(activeTemp.convertedToAbsolute(now, profile))
|
||||
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||
.comment(R.string.let_temp_basal_run))?.run()
|
||||
callback?.result(
|
||||
PumpEnactResult(injector).absolute(activeTemp.convertedToAbsolute(now, profile))
|
||||
.enacted(false).success(true).duration(activeTemp.plannedRemainingMinutes)
|
||||
.comment(R.string.let_temp_basal_run)
|
||||
)?.run()
|
||||
} else {
|
||||
aapsLogger.debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()")
|
||||
uel.log(Action.TEMP_BASAL, Sources.Loop,
|
||||
uel.log(
|
||||
Action.TEMP_BASAL, Sources.Loop,
|
||||
ValueWithUnit.UnitPerHour(request.rate),
|
||||
ValueWithUnit.Minute(request.duration))
|
||||
ValueWithUnit.Minute(request.duration)
|
||||
)
|
||||
commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile, PumpSync.TemporaryBasalType.NORMAL, callback)
|
||||
}
|
||||
}
|
||||
|
@ -581,9 +594,11 @@ class LoopPlugin @Inject constructor(
|
|||
val lastBolusTime = repository.getLastBolusRecord()?.timestamp ?: 0L
|
||||
if (lastBolusTime != 0L && lastBolusTime + 3 * 60 * 1000 > System.currentTimeMillis()) {
|
||||
aapsLogger.debug(LTag.APS, "SMB requested but still in 3 min interval")
|
||||
callback?.result(PumpEnactResult(injector)
|
||||
.comment(R.string.smb_frequency_exceeded)
|
||||
.enacted(false).success(false))?.run()
|
||||
callback?.result(
|
||||
PumpEnactResult(injector)
|
||||
.comment(R.string.smb_frequency_exceeded)
|
||||
.enacted(false).success(false)
|
||||
)?.run()
|
||||
return
|
||||
}
|
||||
if (!pump.isInitialized()) {
|
||||
|
@ -619,11 +634,11 @@ class LoopPlugin @Inject constructor(
|
|||
val pump = activePlugin.activePump
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), reason))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
commandQueue.tempBasalAbsolute(0.0, durationInMinutes, true, profile, PumpSync.TemporaryBasalType.EMULATED_PUMP_SUSPEND, object : Callback() {
|
||||
override fun run() {
|
||||
|
@ -655,11 +670,11 @@ class LoopPlugin @Inject constructor(
|
|||
override fun suspendLoop(durationInMinutes: Int) {
|
||||
disposable += repository.runTransactionForResult(InsertAndCancelCurrentOfflineEventTransaction(dateUtil.now(), T.mins(durationInMinutes.toLong()).msecs(), OfflineEvent.Reason.SUSPEND))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated OfflineEvent $it") }
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted OfflineEvent $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving OfflineEvent", it)
|
||||
})
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
|
|
|
@ -51,7 +51,7 @@ class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector)
|
|||
aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: $date", e)
|
||||
}
|
||||
}
|
||||
if (result.has("variable_sens")) variableSens = result.getDouble("variable_sens");
|
||||
if (result.has("variable_sens")) variableSens = result.getDouble("variable_sens")
|
||||
} catch (e: JSONException) {
|
||||
aapsLogger.error(LTag.APS, "Error parsing determine-basal result JSON", e)
|
||||
}
|
||||
|
|
|
@ -194,9 +194,9 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
this.profile.put("current_basal_safety_multiplier", sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0))
|
||||
|
||||
//mProfile.put("high_temptarget_raises_sensitivity", SP.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity));
|
||||
this.profile.put("high_temptarget_raises_sensitivity", false)
|
||||
this.profile.put("high_temptarget_raises_sensitivity", sp.getBoolean(R.string.key_high_temptarget_raises_sensitivity, SMBDefaults.high_temptarget_raises_sensitivity))
|
||||
//mProfile.put("low_temptarget_lowers_sensitivity", SP.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity));
|
||||
this.profile.put("low_temptarget_lowers_sensitivity", false)
|
||||
this.profile.put("low_temptarget_lowers_sensitivity", sp.getBoolean(R.string.key_low_temptarget_lowers_sensitivity, SMBDefaults.low_temptarget_lowers_sensitivity))
|
||||
this.profile.put("sensitivity_raises_target", sp.getBoolean(R.string.key_sensitivity_raises_target, SMBDefaults.sensitivity_raises_target))
|
||||
this.profile.put("resistance_lowers_target", sp.getBoolean(R.string.key_resistance_lowers_target, SMBDefaults.resistance_lowers_target))
|
||||
this.profile.put("adv_target_adjustments", SMBDefaults.adv_target_adjustments)
|
||||
|
@ -222,12 +222,17 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri
|
|||
this.profile.put("enableSMB_after_carbs", smbEnabled && sp.getBoolean(R.string.key_enableSMB_after_carbs, false) && advancedFiltering)
|
||||
this.profile.put("maxSMBBasalMinutes", sp.getInt(R.string.key_smbmaxminutes, SMBDefaults.maxSMBBasalMinutes))
|
||||
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
|
||||
this.profile.put("DynISFAdjust", SafeParse.stringToDouble(sp.getString(R.string.key_DynISFAdjust,"100")))
|
||||
this.profile.put("maxUAMSMBBasalMinutes", sp.getInt(R.string.key_uamsmbmaxminutes, SMBDefaults.maxUAMSMBBasalMinutes))
|
||||
//set the min SMB amount to be the amount set by the pump.
|
||||
this.profile.put("bolus_increment", pumpBolusStep)
|
||||
this.profile.put("carbsReqThreshold", sp.getInt(R.string.key_carbsReqThreshold, SMBDefaults.carbsReqThreshold))
|
||||
this.profile.put("current_basal", basalRate)
|
||||
this.profile.put("temptargetSet", tempTargetSet)
|
||||
this.profile.put("autosens_max", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_max, "1.2")))
|
||||
this.profile.put("autosens_min", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_min, "0.8")))
|
||||
this.profile.put("openapsama_useautosens", sp.getBoolean(R.string.key_openapsama_useautosens, false))
|
||||
//set the min SMB amount to be the amount set by the pump.
|
||||
if (profileFunction.getUnits() == GlucoseUnit.MMOL) {
|
||||
this.profile.put("out_units", "mmol/L")
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ class OpenAPSSMBDynamicISFPlugin @Inject constructor(
|
|||
.pluginName(R.string.openaps_smb_dynamic_isf)
|
||||
.description(R.string.description_smb_dynamic_isf)
|
||||
.shortName(R.string.dynisf_shortname)
|
||||
.preferencesId(R.xml.pref_openapssmbdynamicisf)
|
||||
.setDefault(false)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,23 +10,26 @@ import android.widget.*
|
|||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.PreferencesActivity
|
||||
import info.nightscout.androidaps.activities.SingleFragmentActivity
|
||||
import info.nightscout.androidaps.databinding.ConfigbuilderFragmentBinding
|
||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.PREFERENCES
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import java.util.*
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConfigBuilderFragment : DaggerFragment() {
|
||||
|
@ -44,48 +47,36 @@ class ConfigBuilderFragment : DaggerFragment() {
|
|||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private val pluginViewHolders = ArrayList<PluginViewHolder>()
|
||||
|
||||
private var inMenu = false
|
||||
private var queryingProtection = false
|
||||
private var _binding: ConfigbuilderFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = ConfigbuilderFragmentBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES))
|
||||
binding.mainLayout.visibility = View.GONE
|
||||
else
|
||||
binding.unlock.visibility = View.GONE
|
||||
|
||||
binding.unlock.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, {
|
||||
activity.runOnUiThread {
|
||||
binding.mainLayout.visibility = View.VISIBLE
|
||||
binding.unlock.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
val parentClass = this.activity?.let { it::class.java }
|
||||
inMenu = parentClass == SingleFragmentActivity::class.java
|
||||
updateProtectedUi()
|
||||
binding.unlock.setOnClickListener { queryProtection() }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (inMenu) queryProtection() else updateProtectedUi()
|
||||
disposable += rxBus
|
||||
.toObservable(EventConfigBuilderUpdateGui::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({
|
||||
for (pluginViewHolder in pluginViewHolders) pluginViewHolder.update()
|
||||
}, fabricPrivacy::logException)
|
||||
for (pluginViewHolder in pluginViewHolders) pluginViewHolder.update()
|
||||
}, fabricPrivacy::logException)
|
||||
updateGUI()
|
||||
}
|
||||
|
||||
|
@ -215,4 +206,21 @@ class ConfigBuilderFragment : DaggerFragment() {
|
|||
return type == PluginType.GENERAL || type == PluginType.CONSTRAINTS || type == PluginType.LOOP
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateProtectedUi() {
|
||||
val isLocked = protectionCheck.isLocked(PREFERENCES)
|
||||
binding.mainLayout.visibility = isLocked.not().toVisibility()
|
||||
binding.unlock.visibility = isLocked.toVisibility()
|
||||
}
|
||||
|
||||
private fun queryProtection() {
|
||||
val isLocked = protectionCheck.isLocked(PREFERENCES)
|
||||
if (isLocked && !queryingProtection) {
|
||||
activity?.let { activity ->
|
||||
queryingProtection = true
|
||||
val doUpdate = { activity.runOnUiThread { queryingProtection = false; updateProtectedUi() } }
|
||||
protectionCheck.queryProtection(activity, PREFERENCES, doUpdate, doUpdate, doUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,6 +169,9 @@ class PluginStore @Inject constructor(
|
|||
override val activeSafety: Safety
|
||||
get() = getSpecificPluginsListByInterface(Safety::class.java).first() as Safety
|
||||
|
||||
override val activeIobCobCalculator: IobCobCalculator
|
||||
get() = getSpecificPluginsListByInterface(IobCobCalculator::class.java).first() as IobCobCalculator
|
||||
|
||||
override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins)
|
||||
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ class ObjectivesFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
holder.binding.accomplished.text = rh.gs(R.string.accomplished, dateUtil.dateAndTimeString(objective.accomplishedOn))
|
||||
holder.binding.accomplished.setTextColor(-0x3e3e3f)
|
||||
holder.binding.accomplished.setTextColor(rh.gac(context,R.attr.defaultTextColor))
|
||||
holder.binding.verify.setOnClickListener {
|
||||
receiverStatusStore.updateNetworkStatus()
|
||||
if (binding.fake.isChecked) {
|
||||
|
|
|
@ -109,29 +109,29 @@ class SafetyPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun applyBasalConstraints(absoluteRate: Constraint<Double>, profile: Profile): Constraint<Double> {
|
||||
absoluteRate.setIfGreater(aapsLogger, 0.0, String.format(rh.gs(R.string.limitingbasalratio), 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
absoluteRate.setIfGreater(aapsLogger, 0.0, rh.gs(R.string.limitingbasalratio, 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
if (config.APS) {
|
||||
var maxBasal = sp.getDouble(R.string.key_openapsma_max_basal, 1.0)
|
||||
if (maxBasal < profile.getMaxDailyBasal()) {
|
||||
maxBasal = profile.getMaxDailyBasal()
|
||||
absoluteRate.addReason(rh.gs(R.string.increasingmaxbasal), this)
|
||||
}
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxBasal, String.format(rh.gs(R.string.limitingbasalratio), maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxBasal,rh.gs(R.string.limitingbasalratio, maxBasal, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
|
||||
// Check percentRate but absolute rate too, because we know real current basal in pump
|
||||
val maxBasalMultiplier = sp.getDouble(R.string.key_openapsama_current_basal_safety_multiplier, 4.0)
|
||||
val maxFromBasalMultiplier = floor(maxBasalMultiplier * profile.getBasal() * 100) / 100
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxFromBasalMultiplier, String.format(rh.gs(R.string.limitingbasalratio), maxFromBasalMultiplier, rh.gs(R.string.maxbasalmultiplier)), this)
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxFromBasalMultiplier, rh.gs(R.string.limitingbasalratio, maxFromBasalMultiplier, rh.gs(R.string.maxbasalmultiplier)), this)
|
||||
val maxBasalFromDaily = sp.getDouble(R.string.key_openapsama_max_daily_safety_multiplier, 3.0)
|
||||
val maxFromDaily = floor(profile.getMaxDailyBasal() * maxBasalFromDaily * 100) / 100
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily, String.format(rh.gs(R.string.limitingbasalratio), maxFromDaily, rh.gs(R.string.maxdailybasalmultiplier)), this)
|
||||
absoluteRate.setIfSmaller(aapsLogger, maxFromDaily,rh.gs(R.string.limitingbasalratio, maxFromDaily, rh.gs(R.string.maxdailybasalmultiplier)), this)
|
||||
}
|
||||
absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(), String.format(rh.gs(R.string.limitingbasalratio), hardLimits.maxBasal(), rh.gs(R.string.hardlimit)), this)
|
||||
absoluteRate.setIfSmaller(aapsLogger, hardLimits.maxBasal(),rh.gs(R.string.limitingbasalratio, hardLimits.maxBasal(), rh.gs(R.string.hardlimit)), this)
|
||||
val pump = activePlugin.activePump
|
||||
// check for pump max
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.ABSOLUTE) {
|
||||
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0
|
||||
absoluteRate.setIfSmaller(aapsLogger, pumpLimit, String.format(rh.gs(R.string.limitingbasalratio), pumpLimit, rh.gs(R.string.pumplimit)), this)
|
||||
absoluteRate.setIfSmaller(aapsLogger, pumpLimit, rh.gs(R.string.limitingbasalratio, pumpLimit, rh.gs(R.string.pumplimit)), this)
|
||||
}
|
||||
|
||||
// do rounding
|
||||
|
@ -151,19 +151,19 @@ class SafetyPlugin @Inject constructor(
|
|||
val pump = activePlugin.activePump
|
||||
var percentRateAfterConst = java.lang.Double.valueOf(absoluteConstraint.value() / currentBasal * 100).toInt()
|
||||
percentRateAfterConst = if (percentRateAfterConst < 100) Round.ceilTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt() else Round.floorTo(percentRateAfterConst.toDouble(), pump.pumpDescription.tempPercentStep.toDouble()).toInt()
|
||||
percentRate.set(aapsLogger, percentRateAfterConst, String.format(rh.gs(R.string.limitingpercentrate), percentRateAfterConst, rh.gs(R.string.pumplimit)), this)
|
||||
percentRate.set(aapsLogger, percentRateAfterConst, rh.gs(R.string.limitingpercentrate, percentRateAfterConst, rh.gs(R.string.pumplimit)), this)
|
||||
if (pump.pumpDescription.tempBasalStyle == PumpDescription.PERCENT) {
|
||||
val pumpLimit = pump.pumpDescription.pumpType.tbrSettings?.maxDose ?: 0.0
|
||||
percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), String.format(rh.gs(R.string.limitingbasalratio), pumpLimit, rh.gs(R.string.pumplimit)), this)
|
||||
percentRate.setIfSmaller(aapsLogger, pumpLimit.toInt(), rh.gs(R.string.limitingbasalratio, pumpLimit, rh.gs(R.string.pumplimit)), this)
|
||||
}
|
||||
return percentRate
|
||||
}
|
||||
|
||||
override fun applyBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
|
||||
insulin.setIfGreater(aapsLogger, 0.0, String.format(rh.gs(R.string.limitingbolus), 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
insulin.setIfGreater(aapsLogger, 0.0, rh.gs(R.string.limitingbolus, 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
|
||||
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(rh.gs(R.string.limitingbolus), maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(rh.gs(R.string.limitingbolus), hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
|
||||
insulin.setIfSmaller(aapsLogger, maxBolus, rh.gs(R.string.limitingbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), rh.gs(R.string.limitingbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
|
||||
val pump = activePlugin.activePump
|
||||
val rounded = pump.pumpDescription.pumpType.determineCorrectBolusSize(insulin.value())
|
||||
insulin.setIfDifferent(aapsLogger, rounded, rh.gs(R.string.pumplimit), this)
|
||||
|
@ -171,10 +171,10 @@ class SafetyPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun applyExtendedBolusConstraints(insulin: Constraint<Double>): Constraint<Double> {
|
||||
insulin.setIfGreater(aapsLogger, 0.0, String.format(rh.gs(R.string.limitingextendedbolus), 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
insulin.setIfGreater(aapsLogger, 0.0, rh.gs(R.string.limitingextendedbolus, 0.0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
val maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0)
|
||||
insulin.setIfSmaller(aapsLogger, maxBolus, String.format(rh.gs(R.string.limitingextendedbolus), maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), String.format(rh.gs(R.string.limitingextendedbolus), hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
|
||||
insulin.setIfSmaller(aapsLogger, maxBolus, rh.gs(R.string.limitingextendedbolus, maxBolus, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
insulin.setIfSmaller(aapsLogger, hardLimits.maxBolus(), rh.gs(R.string.limitingextendedbolus, hardLimits.maxBolus(), rh.gs(R.string.hardlimit)), this)
|
||||
val pump = activePlugin.activePump
|
||||
val rounded = pump.pumpDescription.pumpType.determineCorrectExtendedBolusSize(insulin.value())
|
||||
insulin.setIfDifferent(aapsLogger, rounded, rh.gs(R.string.pumplimit), this)
|
||||
|
@ -182,9 +182,9 @@ class SafetyPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
override fun applyCarbsConstraints(carbs: Constraint<Int>): Constraint<Int> {
|
||||
carbs.setIfGreater(aapsLogger, 0, String.format(rh.gs(R.string.limitingcarbs), 0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
carbs.setIfGreater(aapsLogger, 0, rh.gs(R.string.limitingcarbs, 0, rh.gs(R.string.itmustbepositivevalue)), this)
|
||||
val maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48)
|
||||
carbs.setIfSmaller(aapsLogger, maxCarbs, String.format(rh.gs(R.string.limitingcarbs), maxCarbs, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
carbs.setIfSmaller(aapsLogger, maxCarbs, rh.gs(R.string.limitingcarbs, maxCarbs, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
return carbs
|
||||
}
|
||||
|
||||
|
@ -192,11 +192,11 @@ class SafetyPlugin @Inject constructor(
|
|||
val apsMode = sp.getString(R.string.key_aps_mode, "open")
|
||||
val maxIobPref: Double = if (openAPSSMBPlugin.isEnabled() || OpenAPSSMBDynamicISFPlugin.isEnabled()) sp.getDouble(R.string.key_openapssmb_max_iob, 3.0) else sp.getDouble(R.string
|
||||
.key_openapsma_max_iob, 1.5)
|
||||
maxIob.setIfSmaller(aapsLogger, maxIobPref, String.format(rh.gs(R.string.limitingiob), maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
if (openAPSAMAPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), String.format(rh.gs(R.string.limitingiob), hardLimits.maxIobAMA(), rh.gs(R.string.hardlimit)), this)
|
||||
if (openAPSSMBPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(rh.gs(R.string.limitingiob), hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
|
||||
if (OpenAPSSMBDynamicISFPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), String.format(rh.gs(R.string.limitingiob), hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
|
||||
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, HardLimits.MAX_IOB_LGS, String.format(rh.gs(R.string.limitingiob), HardLimits.MAX_IOB_LGS, rh.gs(R.string.lowglucosesuspend)), this)
|
||||
maxIob.setIfSmaller(aapsLogger, maxIobPref, rh.gs(R.string.limitingiob, maxIobPref, rh.gs(R.string.maxvalueinpreferences)), this)
|
||||
if (openAPSAMAPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobAMA(), rh.gs(R.string.limitingiob, hardLimits.maxIobAMA(), rh.gs(R.string.hardlimit)), this)
|
||||
if (openAPSSMBPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), rh.gs(R.string.limitingiob, hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
|
||||
if (OpenAPSSMBDynamicISFPlugin.isEnabled()) maxIob.setIfSmaller(aapsLogger, hardLimits.maxIobSMB(), rh.gs(R.string.limitingiob, hardLimits.maxIobSMB(), rh.gs(R.string.hardlimit)), this)
|
||||
if (apsMode == "lgs") maxIob.setIfSmaller(aapsLogger, HardLimits.MAX_IOB_LGS, rh.gs(R.string.limitingiob, HardLimits.MAX_IOB_LGS, rh.gs(R.string.lowglucosesuspend)), this)
|
||||
return maxIob
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,8 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
import info.nightscout.androidaps.activities.HistoryBrowseActivity
|
||||
|
@ -20,7 +18,7 @@ import info.nightscout.androidaps.database.AppRepository
|
|||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.diaconn.DiaconnG8Plugin
|
||||
import info.nightscout.androidaps.databinding.ActionsFragmentBinding
|
||||
import info.nightscout.androidaps.dialogs.*
|
||||
import info.nightscout.androidaps.events.EventCustomActionsChanged
|
||||
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
||||
|
@ -36,7 +34,6 @@ import info.nightscout.androidaps.logging.UserEntryLogger
|
|||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
|
||||
import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.skins.SkinProvider
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
|
@ -81,88 +78,47 @@ class ActionsFragment : DaggerFragment() {
|
|||
|
||||
private val pumpCustomActions = HashMap<String, CustomAction>()
|
||||
private val pumpCustomButtons = ArrayList<SingleClickButton>()
|
||||
private var smallWidth = false
|
||||
private var smallHeight = false
|
||||
private lateinit var dm: DisplayMetrics
|
||||
|
||||
private var buttonsLayout: LinearLayout? = null
|
||||
private var profileSwitch: SingleClickButton? = null
|
||||
private var tempTarget: SingleClickButton? = null
|
||||
private var extendedBolus: SingleClickButton? = null
|
||||
private var extendedBolusCancel: SingleClickButton? = null
|
||||
private var setTempBasal: SingleClickButton? = null
|
||||
private var cancelTempBasal: SingleClickButton? = null
|
||||
private var fill: SingleClickButton? = null
|
||||
private var historyBrowser: SingleClickButton? = null
|
||||
private var tddStats: SingleClickButton? = null
|
||||
private var pumpBatteryChange: SingleClickButton? = null
|
||||
private var _binding: ActionsFragmentBinding? = null
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var cannulaAge: TextView? = null
|
||||
private var insulinAge: TextView? = null
|
||||
private var reservoirLevel: TextView? = null
|
||||
private var sensorAge: TextView? = null
|
||||
private var sensorLevel: TextView? = null
|
||||
private var pbAge: TextView? = null
|
||||
private var batteryLevel: TextView? = null
|
||||
private var sensorLevelLabel: TextView? = null
|
||||
private var insulinLevelLabel: TextView? = null
|
||||
private var pbLevelLabel: TextView? = null
|
||||
private var cannulaOrPatch: TextView? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
//check screen width
|
||||
dm = DisplayMetrics()
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
|
||||
@Suppress("DEPRECATION")
|
||||
activity?.display?.getRealMetrics(dm)
|
||||
else
|
||||
} else {
|
||||
@Suppress("DEPRECATION") activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
||||
|
||||
val screenWidth = dm.widthPixels
|
||||
val screenHeight = dm.heightPixels
|
||||
smallWidth = screenWidth <= Constants.SMALL_WIDTH
|
||||
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
|
||||
val landscape = screenHeight < screenWidth
|
||||
|
||||
return inflater.inflate(skinProvider.activeSkin().actionsLayout(landscape, smallWidth), container, false)
|
||||
}
|
||||
_binding = ActionsFragmentBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
buttonsLayout = view.findViewById(R.id.action_buttons_layout)
|
||||
profileSwitch = view.findViewById(R.id.actions_profileswitch)
|
||||
tempTarget = view.findViewById(R.id.actions_temptarget)
|
||||
extendedBolus = view.findViewById(R.id.actions_extendedbolus)
|
||||
extendedBolusCancel = view.findViewById(R.id.actions_extendedbolus_cancel)
|
||||
setTempBasal = view.findViewById(R.id.actions_settempbasal)
|
||||
cancelTempBasal = view.findViewById(R.id.actions_canceltempbasal)
|
||||
fill = view.findViewById(R.id.actions_fill)
|
||||
historyBrowser = view.findViewById(R.id.actions_historybrowser)
|
||||
tddStats = view.findViewById(R.id.actions_tddstats)
|
||||
pumpBatteryChange = view.findViewById(R.id.actions_pumpbatterychange)
|
||||
skinProvider.activeSkin().preProcessLandscapeActionsLayout(dm, binding)
|
||||
|
||||
cannulaAge = view.findViewById(R.id.cannula_age)
|
||||
insulinAge = view.findViewById(R.id.insulin_age)
|
||||
reservoirLevel = view.findViewById(R.id.reservoir_level)
|
||||
sensorAge = view.findViewById(R.id.sensor_age)
|
||||
sensorLevel = view.findViewById(R.id.sensor_level)
|
||||
pbAge = view.findViewById(R.id.pb_age)
|
||||
batteryLevel = view.findViewById(R.id.battery_level)
|
||||
sensorLevelLabel = view.findViewById(R.id.sensor_level_label)
|
||||
insulinLevelLabel = view.findViewById(R.id.insulin_level_label)
|
||||
pbLevelLabel = view.findViewById(R.id.pb_level_label)
|
||||
cannulaOrPatch = view.findViewById(R.id.cannula_or_patch)
|
||||
|
||||
profileSwitch?.setOnClickListener {
|
||||
ProfileSwitchDialog().show(childFragmentManager, "ProfileSwitchDialog")
|
||||
binding.profileSwitch.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(
|
||||
activity,
|
||||
ProtectionCheck.Protection.BOLUS,
|
||||
UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "ProfileSwitchDialog")})
|
||||
}
|
||||
}
|
||||
tempTarget?.setOnClickListener {
|
||||
TempTargetDialog().show(childFragmentManager, "Actions")
|
||||
binding.tempTarget.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(
|
||||
activity,
|
||||
ProtectionCheck.Protection.BOLUS,
|
||||
UIRunnable { TempTargetDialog().show(childFragmentManager, "Actions") })
|
||||
}
|
||||
}
|
||||
extendedBolus?.setOnClickListener {
|
||||
binding.extendedBolus.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
OKDialog.showConfirmation(
|
||||
|
@ -174,7 +130,7 @@ class ActionsFragment : DaggerFragment() {
|
|||
})
|
||||
}
|
||||
}
|
||||
extendedBolusCancel?.setOnClickListener {
|
||||
binding.extendedBolusCancel.setOnClickListener {
|
||||
if (iobCobCalculator.getExtendedBolus(dateUtil.now()) != null) {
|
||||
uel.log(Action.CANCEL_EXTENDED_BOLUS, Sources.Actions)
|
||||
commandQueue.cancelExtended(object : Callback() {
|
||||
|
@ -186,10 +142,15 @@ class ActionsFragment : DaggerFragment() {
|
|||
})
|
||||
}
|
||||
}
|
||||
setTempBasal?.setOnClickListener {
|
||||
TempBasalDialog().show(childFragmentManager, "Actions")
|
||||
binding.setTempBasal.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(
|
||||
activity,
|
||||
ProtectionCheck.Protection.BOLUS,
|
||||
UIRunnable { TempBasalDialog().show(childFragmentManager, "Actions") })
|
||||
}
|
||||
}
|
||||
cancelTempBasal?.setOnClickListener {
|
||||
binding.cancelTempBasal.setOnClickListener {
|
||||
if (iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now()) != null) {
|
||||
uel.log(Action.CANCEL_TEMP_BASAL, Sources.Actions)
|
||||
commandQueue.cancelTempBasal(true, object : Callback() {
|
||||
|
@ -201,32 +162,32 @@ class ActionsFragment : DaggerFragment() {
|
|||
})
|
||||
}
|
||||
}
|
||||
fill?.setOnClickListener {
|
||||
binding.fill.setOnClickListener {
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { FillDialog().show(childFragmentManager, "FillDialog") })
|
||||
}
|
||||
}
|
||||
historyBrowser?.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
|
||||
tddStats?.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
|
||||
view.findViewById<SingleClickButton>(R.id.actions_bgcheck).setOnClickListener {
|
||||
binding.historyBrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
|
||||
binding.tddStats.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
|
||||
binding.bgCheck.setOnClickListener {
|
||||
CareDialog().setOptions(CareDialog.EventType.BGCHECK, R.string.careportal_bgcheck).show(childFragmentManager, "Actions")
|
||||
}
|
||||
view.findViewById<SingleClickButton>(R.id.actions_cgmsensorinsert).setOnClickListener {
|
||||
binding.cgmSensorInsert.setOnClickListener {
|
||||
CareDialog().setOptions(CareDialog.EventType.SENSOR_INSERT, R.string.careportal_cgmsensorinsert).show(childFragmentManager, "Actions")
|
||||
}
|
||||
pumpBatteryChange?.setOnClickListener {
|
||||
binding.pumpBatteryChange.setOnClickListener {
|
||||
CareDialog().setOptions(CareDialog.EventType.BATTERY_CHANGE, R.string.careportal_pumpbatterychange).show(childFragmentManager, "Actions")
|
||||
}
|
||||
view.findViewById<SingleClickButton>(R.id.actions_note).setOnClickListener {
|
||||
binding.note.setOnClickListener {
|
||||
CareDialog().setOptions(CareDialog.EventType.NOTE, R.string.careportal_note).show(childFragmentManager, "Actions")
|
||||
}
|
||||
view.findViewById<SingleClickButton>(R.id.actions_exercise).setOnClickListener {
|
||||
binding.exercise.setOnClickListener {
|
||||
CareDialog().setOptions(CareDialog.EventType.EXERCISE, R.string.careportal_exercise).show(childFragmentManager, "Actions")
|
||||
}
|
||||
view.findViewById<SingleClickButton>(R.id.actions_question).setOnClickListener {
|
||||
binding.question.setOnClickListener {
|
||||
CareDialog().setOptions(CareDialog.EventType.QUESTION, R.string.careportal_question).show(childFragmentManager, "Actions")
|
||||
}
|
||||
view.findViewById<SingleClickButton>(R.id.actions_announcement).setOnClickListener {
|
||||
binding.announcement.setOnClickListener {
|
||||
CareDialog().setOptions(CareDialog.EventType.ANNOUNCEMENT, R.string.careportal_announcement).show(childFragmentManager, "Actions")
|
||||
}
|
||||
|
||||
|
@ -265,13 +226,18 @@ class ActionsFragment : DaggerFragment() {
|
|||
disposable.clear()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun updateGui() {
|
||||
|
||||
val profile = profileFunction.getProfile()
|
||||
val pump = activePlugin.activePump
|
||||
|
||||
profileSwitch?.visibility = (
|
||||
binding.profileSwitch.visibility = (
|
||||
activePlugin.activeProfileSource.profile != null &&
|
||||
pump.pumpDescription.isSetBasalProfileCapable &&
|
||||
pump.isInitialized() &&
|
||||
|
@ -279,60 +245,58 @@ class ActionsFragment : DaggerFragment() {
|
|||
!loop.isDisconnected).toVisibility()
|
||||
|
||||
if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || loop.isDisconnected || pump.isFakingTempsByExtendedBoluses || config.NSCLIENT) {
|
||||
extendedBolus?.visibility = View.GONE
|
||||
extendedBolusCancel?.visibility = View.GONE
|
||||
binding.extendedBolus.visibility = View.GONE
|
||||
binding.extendedBolusCancel.visibility = View.GONE
|
||||
} else {
|
||||
val activeExtendedBolus = repository.getExtendedBolusActiveAt(dateUtil.now()).blockingGet()
|
||||
if (activeExtendedBolus is ValueWrapper.Existing) {
|
||||
extendedBolus?.visibility = View.GONE
|
||||
extendedBolusCancel?.visibility = View.VISIBLE
|
||||
binding.extendedBolus.visibility = View.GONE
|
||||
binding.extendedBolusCancel.visibility = View.VISIBLE
|
||||
@Suppress("SetTextI18n")
|
||||
extendedBolusCancel?.text = rh.gs(R.string.cancel) + " " + activeExtendedBolus.value.toStringMedium(dateUtil)
|
||||
binding.extendedBolusCancel.text = rh.gs(R.string.cancel) + " " + activeExtendedBolus.value.toStringMedium(dateUtil)
|
||||
} else {
|
||||
extendedBolus?.visibility = View.VISIBLE
|
||||
extendedBolusCancel?.visibility = View.GONE
|
||||
binding.extendedBolus.visibility = View.VISIBLE
|
||||
binding.extendedBolusCancel.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized() || pump.isSuspended() || loop.isDisconnected || config.NSCLIENT) {
|
||||
setTempBasal?.visibility = View.GONE
|
||||
cancelTempBasal?.visibility = View.GONE
|
||||
binding.setTempBasal.visibility = View.GONE
|
||||
binding.cancelTempBasal.visibility = View.GONE
|
||||
} else {
|
||||
val activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())
|
||||
if (activeTemp != null) {
|
||||
setTempBasal?.visibility = View.GONE
|
||||
cancelTempBasal?.visibility = View.VISIBLE
|
||||
binding.setTempBasal.visibility = View.GONE
|
||||
binding.cancelTempBasal.visibility = View.VISIBLE
|
||||
@Suppress("SetTextI18n")
|
||||
cancelTempBasal?.text = rh.gs(R.string.cancel) + " " + activeTemp.toStringShort()
|
||||
binding.cancelTempBasal.text = rh.gs(R.string.cancel) + " " + activeTemp.toStringShort()
|
||||
} else {
|
||||
setTempBasal?.visibility = View.VISIBLE
|
||||
cancelTempBasal?.visibility = View.GONE
|
||||
binding.setTempBasal.visibility = View.VISIBLE
|
||||
binding.cancelTempBasal.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
val activeBgSource = activePlugin.activeBgSource
|
||||
historyBrowser?.visibility = (profile != null).toVisibility()
|
||||
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility()
|
||||
if (pump is DiaconnG8Plugin) {
|
||||
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable && !pump.isBatteryChangeLoggingEnabled()).toVisibility()
|
||||
} else {
|
||||
pumpBatteryChange?.visibility =
|
||||
(pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
|
||||
}
|
||||
tempTarget?.visibility = (profile != null && !loop.isDisconnected).toVisibility()
|
||||
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
|
||||
binding.historyBrowser.visibility = (profile != null).toVisibility()
|
||||
binding.fill.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized() && !pump.isSuspended()).toVisibility()
|
||||
binding.pumpBatteryChange.visibility = (pump.pumpDescription.isBatteryReplaceable || pump.isBatteryChangeLoggingEnabled()).toVisibility()
|
||||
binding.tempTarget.visibility = (profile != null && !loop.isDisconnected).toVisibility()
|
||||
binding.tddStats.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
|
||||
val isPatchPump = pump.pumpDescription.isPatchPump
|
||||
binding.status.apply {
|
||||
cannulaOrPatch.text = if (isPatchPump) rh.gs(R.string.patch_pump) else rh.gs(R.string.cannula)
|
||||
val imageResource = if (isPatchPump) R.drawable.ic_patch_pump_outline else R.drawable.ic_cp_age_cannula
|
||||
cannulaOrPatch.setCompoundDrawablesWithIntrinsicBounds(imageResource, 0, 0, 0)
|
||||
batteryLayout.visibility = (!isPatchPump || pump.pumpDescription.useHardwareLink).toVisibility()
|
||||
|
||||
cannulaOrPatch?.text = if (pump.pumpDescription.isPatchPump) rh.gs(R.string.patch_pump) else rh.gs(R.string.cannula)
|
||||
val imageResource = if (pump.pumpDescription.isPatchPump) R.drawable.ic_patch_pump_outline else R.drawable.ic_cp_age_cannula
|
||||
cannulaOrPatch?.setCompoundDrawablesWithIntrinsicBounds(imageResource, 0, 0, 0)
|
||||
|
||||
if (!config.NSCLIENT) {
|
||||
statusLightHandler.updateStatusLights(cannulaAge, insulinAge, reservoirLevel, sensorAge, sensorLevel, pbAge, batteryLevel)
|
||||
sensorLevelLabel?.text = if (activeBgSource.sensorBatteryLevel == -1) "" else rh.gs(R.string.careportal_level_label)
|
||||
} else {
|
||||
statusLightHandler.updateStatusLights(cannulaAge, insulinAge, null, sensorAge, null, pbAge, null)
|
||||
sensorLevelLabel?.text = ""
|
||||
insulinLevelLabel?.text = ""
|
||||
pbLevelLabel?.text = ""
|
||||
if (!config.NSCLIENT) {
|
||||
statusLightHandler.updateStatusLights(cannulaAge, insulinAge, reservoirLevel, sensorAge, sensorLevel, pbAge, batteryLevel)
|
||||
sensorLevelLabel.text = if (activeBgSource.sensorBatteryLevel == -1) "" else rh.gs(R.string.careportal_level_label)
|
||||
} else {
|
||||
statusLightHandler.updateStatusLights(cannulaAge, insulinAge, null, sensorAge, null, pbAge, null)
|
||||
sensorLevelLabel.text = ""
|
||||
insulinLevelLabel.text = ""
|
||||
pbLevelLabel.text = ""
|
||||
}
|
||||
}
|
||||
checkPumpCustomActions()
|
||||
|
||||
|
@ -365,7 +329,7 @@ class ActionsFragment : DaggerFragment() {
|
|||
val top = activity?.let { ContextCompat.getDrawable(it, customAction.iconResourceId) }
|
||||
btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null)
|
||||
|
||||
buttonsLayout?.addView(btn)
|
||||
binding.buttonsLayout.addView(btn)
|
||||
|
||||
this.pumpCustomActions[rh.gs(customAction.name)] = customAction
|
||||
this.pumpCustomButtons.add(btn)
|
||||
|
@ -373,7 +337,7 @@ class ActionsFragment : DaggerFragment() {
|
|||
}
|
||||
|
||||
private fun removePumpCustomActions() {
|
||||
for (customButton in pumpCustomButtons) buttonsLayout?.removeView(customButton)
|
||||
for (customButton in pumpCustomButtons) binding.buttonsLayout.removeView(customButton)
|
||||
pumpCustomButtons.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@ import android.content.pm.ResolveInfo
|
|||
import android.os.Bundle
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.extensions.durationInMinutes
|
||||
import info.nightscout.androidaps.extensions.toStringFull
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.DeviceStatusData
|
||||
|
@ -25,6 +24,8 @@ import info.nightscout.androidaps.utils.DefaultValueHelper
|
|||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -68,26 +69,6 @@ class DataBroadcastPlugin @Inject constructor(
|
|||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendData(it) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendData(it) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendData(it) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventTreatmentChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendData(it) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendData(it) }, fabricPrivacy::logException)
|
||||
)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.food
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
|
@ -24,18 +23,18 @@ import info.nightscout.androidaps.databinding.FoodFragmentBinding
|
|||
import info.nightscout.androidaps.databinding.FoodItemBinding
|
||||
import info.nightscout.androidaps.dialogs.WizardDialog
|
||||
import info.nightscout.androidaps.events.EventFoodDatabaseChanged
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientRestart
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.ui.UIRunnable
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import io.reactivex.rxjava3.core.Completable
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -43,7 +42,6 @@ import io.reactivex.rxjava3.kotlin.subscribeBy
|
|||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class FoodFragment : DaggerFragment() {
|
||||
|
||||
|
@ -66,10 +64,8 @@ class FoodFragment : DaggerFragment() {
|
|||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = FoodFragmentBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
FoodFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -80,8 +76,10 @@ class FoodFragment : DaggerFragment() {
|
|||
binding.refreshFromNightscout.setOnClickListener {
|
||||
context?.let { context ->
|
||||
OKDialog.showConfirmation(context, rh.gs(R.string.refresheventsfromnightscout) + " ?", {
|
||||
uel.log(Action.FOOD, Sources.Food, rh.gs(R.string.refresheventsfromnightscout),
|
||||
ValueWithUnit.SimpleString(rh.gsNotLocalised(R.string.refresheventsfromnightscout)))
|
||||
uel.log(
|
||||
Action.FOOD, Sources.Food, rh.gs(R.string.refresheventsfromnightscout),
|
||||
ValueWithUnit.SimpleString(rh.gsNotLocalised(R.string.refresheventsfromnightscout))
|
||||
)
|
||||
disposable += Completable.fromAction { repository.deleteAllFoods() }
|
||||
.subscribeOn(aapsSchedulers.io)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
|
@ -95,32 +93,14 @@ class FoodFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
binding.clearfilter.setOnClickListener {
|
||||
binding.filterinputLayout.setEndIconOnClickListener {
|
||||
binding.filter.setText("")
|
||||
binding.category.setSelection(0)
|
||||
binding.subcategory.setSelection(0)
|
||||
binding.categoryList.setText(rh.gs(R.string.none), false)
|
||||
binding.subcategoryList.setText(rh.gs(R.string.none), false)
|
||||
filterData()
|
||||
}
|
||||
binding.category.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
fillSubcategories()
|
||||
filterData()
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||
fillSubcategories()
|
||||
filterData()
|
||||
}
|
||||
}
|
||||
binding.subcategory.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
filterData()
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||
filterData()
|
||||
}
|
||||
}
|
||||
binding.categoryList.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, _ -> fillSubcategories(); filterData() }
|
||||
binding.subcategoryList.onItemClickListener = AdapterView.OnItemClickListener { _, _, _, _ -> filterData() }
|
||||
binding.filter.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
|
@ -134,12 +114,11 @@ class FoodFragment : DaggerFragment() {
|
|||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable.add(rxBus
|
||||
disposable += rxBus
|
||||
.toObservable(EventFoodDatabaseChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.subscribe({ swapAdapter() }, fabricPrivacy::logException)
|
||||
)
|
||||
swapAdapter()
|
||||
}
|
||||
|
||||
|
@ -178,13 +157,13 @@ class FoodFragment : DaggerFragment() {
|
|||
val categories = ArrayList(catSet)
|
||||
categories.add(0, rh.gs(R.string.none))
|
||||
context?.let { context ->
|
||||
val adapterCategories = ArrayAdapter(context, R.layout.spinner_centered, categories)
|
||||
binding.category.adapter = adapterCategories
|
||||
binding.categoryList.setAdapter(ArrayAdapter(context, R.layout.spinner_centered, categories))
|
||||
binding.categoryList.setText(rh.gs(R.string.none), false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillSubcategories() {
|
||||
val categoryFilter = binding.category.selectedItem.toString()
|
||||
val categoryFilter = binding.categoryList.text.toString()
|
||||
val subCatSet: MutableSet<CharSequence> = HashSet()
|
||||
if (categoryFilter != rh.gs(R.string.none)) {
|
||||
for (f in unfiltered) {
|
||||
|
@ -198,17 +177,15 @@ class FoodFragment : DaggerFragment() {
|
|||
val subcategories = ArrayList(subCatSet)
|
||||
subcategories.add(0, rh.gs(R.string.none))
|
||||
context?.let { context ->
|
||||
val adapterSubcategories = ArrayAdapter(context, R.layout.spinner_centered, subcategories)
|
||||
binding.subcategory.adapter = adapterSubcategories
|
||||
binding.subcategoryList.setAdapter(ArrayAdapter(context, R.layout.spinner_centered, subcategories))
|
||||
binding.subcategoryList.setText(rh.gs(R.string.none), false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterData() {
|
||||
val textFilter = binding.filter.text.toString()
|
||||
val categoryFilter = binding.category.selectedItem?.toString()
|
||||
?: rh.gs(R.string.none)
|
||||
val subcategoryFilter = binding.subcategory.selectedItem?.toString()
|
||||
?: rh.gs(R.string.none)
|
||||
val categoryFilter = binding.categoryList.text.toString()
|
||||
val subcategoryFilter = binding.subcategoryList.text.toString()
|
||||
val newFiltered = ArrayList<Food>()
|
||||
for (f in unfiltered) {
|
||||
if (f.category == null || f.subCategory == null) continue
|
||||
|
@ -267,18 +244,17 @@ class FoodFragment : DaggerFragment() {
|
|||
}, null)
|
||||
}
|
||||
}
|
||||
binding.icCalculator.setOnClickListener { v:View ->
|
||||
binding.icCalculator.setOnClickListener { v: View ->
|
||||
val food = v.tag as Food
|
||||
activity?.let { activity ->
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
if (isAdded) {
|
||||
val wizardDialog = WizardDialog()
|
||||
val bundle = Bundle()
|
||||
bundle.putInt("carbs_input", food.carbs)
|
||||
bundle.putString("notes_input", " ${food.name} - ${food.carbs}g")
|
||||
wizardDialog.setArguments(bundle)
|
||||
wizardDialog.show(childFragmentManager, "Food Item")
|
||||
}
|
||||
if (isAdded)
|
||||
WizardDialog().also { dialog ->
|
||||
dialog.arguments = Bundle().also { bundle ->
|
||||
bundle.putDouble("carbs_input", food.carbs.toDouble())
|
||||
bundle.putString("notes_input", " ${food.name} - ${food.carbs}g")
|
||||
}
|
||||
}.show(childFragmentManager, "Food Item")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.SingleFragmentActivity
|
||||
import info.nightscout.androidaps.dana.database.DanaHistoryDatabase
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
|
@ -14,6 +15,7 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
|||
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
|
||||
import info.nightscout.androidaps.diaconn.database.DiaconnHistoryDatabase
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.insight.database.InsightDatabase
|
||||
import info.nightscout.androidaps.interfaces.DataSyncSelector
|
||||
import info.nightscout.androidaps.interfaces.ImportExportPrefs
|
||||
|
@ -27,6 +29,8 @@ import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
|||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.DashHistoryDatabase
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.history.database.ErosHistoryDatabase
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.PREFERENCES
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.rxjava3.core.Completable.fromAction
|
||||
|
@ -48,6 +52,7 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
@Inject lateinit var diaconnDatabase: DiaconnHistoryDatabase
|
||||
@Inject lateinit var erosDatabase: ErosHistoryDatabase
|
||||
@Inject lateinit var dashDatabase: DashHistoryDatabase
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
@Inject lateinit var dataSyncSelector: DataSyncSelector
|
||||
@Inject lateinit var pumpSync: PumpSync
|
||||
|
@ -55,11 +60,11 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
@Inject lateinit var overviewData: OverviewData
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
private var inMenu = false
|
||||
private var queryingProtection = false
|
||||
private var _binding: MaintenanceFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
@ -69,6 +74,9 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val parentClass = this.activity?.let { it::class.java }
|
||||
inMenu = parentClass == SingleFragmentActivity::class.java
|
||||
updateProtectedUi()
|
||||
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
|
||||
binding.logDelete.setOnClickListener {
|
||||
uel.log(Action.DELETE_LOGS, Sources.Maintenance)
|
||||
|
@ -128,6 +136,13 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.unlock.setOnClickListener { queryProtection() }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (inMenu) queryProtection() else updateProtectedUi()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -136,4 +151,21 @@ class MaintenanceFragment : DaggerFragment() {
|
|||
compositeDisposable.clear()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateProtectedUi() {
|
||||
val isLocked = protectionCheck.isLocked(PREFERENCES)
|
||||
binding.mainLayout.visibility = isLocked.not().toVisibility()
|
||||
binding.unlock.visibility = isLocked.toVisibility()
|
||||
}
|
||||
|
||||
private fun queryProtection() {
|
||||
val isLocked = protectionCheck.isLocked(PREFERENCES)
|
||||
if (isLocked && !queryingProtection) {
|
||||
activity?.let { activity ->
|
||||
queryingProtection = true
|
||||
val doUpdate = { activity.runOnUiThread { queryingProtection = false; updateProtectedUi() } }
|
||||
protectionCheck.queryProtection(activity, PREFERENCES, doUpdate, doUpdate, doUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,6 @@ class MaintenancePlugin @Inject constructor(
|
|||
context.startActivity(emailIntent)
|
||||
}
|
||||
|
||||
//todo replace this with a call on startup of the application, specifically to remove
|
||||
// unnecessary garbage from the log exports
|
||||
fun deleteLogs(keep: Int) {
|
||||
val logDir = File(loggerUtils.logDirectory)
|
||||
val files = logDir.listFiles { _: File?, name: String ->
|
||||
|
|
|
@ -170,8 +170,7 @@ class NSClientPlugin @Inject constructor(
|
|||
|
||||
override fun onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
aapsLogger.debug(LTag.NSCLIENT, "Service is connected")
|
||||
val mLocalBinder = service as NSClientService.LocalBinder
|
||||
@Suppress("UNNECESSARY_SAFE_CALL")
|
||||
val mLocalBinder = service as NSClientService.LocalBinder?
|
||||
nsClientService = mLocalBinder?.serviceInstance // is null when running in roboelectric
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ class NSClientService : DaggerService() {
|
|||
lastAckTime = dateUtil.now()
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientAddAckWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(ack, null))
|
||||
.setInputData(dataWorker.storeInputData(ack))
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ class NSClientService : DaggerService() {
|
|||
lastAckTime = dateUtil.now()
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientUpdateRemoveAckWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(ack, null))
|
||||
.setInputData(dataWorker.storeInputData(ack))
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
@ -483,7 +483,7 @@ class NSClientService : DaggerService() {
|
|||
rxBus.send(EventNSClientNewLog("PROFILE", "profile received"))
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(LocalProfilePlugin.NSProfileWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(profileStoreJson, null))
|
||||
.setInputData(dataWorker.storeInputData(profileStoreJson))
|
||||
.build()
|
||||
)
|
||||
xDripBroadcast.sendProfile(profileStoreJson)
|
||||
|
@ -502,7 +502,7 @@ class NSClientService : DaggerService() {
|
|||
if (addedOrUpdatedTreatments.length() > 0) {
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientAddUpdateWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments, null))
|
||||
.setInputData(dataWorker.storeInputData(addedOrUpdatedTreatments))
|
||||
.build()
|
||||
)
|
||||
xDripBroadcast.sendTreatments(addedOrUpdatedTreatments)
|
||||
|
@ -520,7 +520,7 @@ class NSClientService : DaggerService() {
|
|||
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods"))
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(FoodWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(foods, null))
|
||||
.setInputData(dataWorker.storeInputData(foods))
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ class NSClientService : DaggerService() {
|
|||
if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs"))
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(mbgArray, null))
|
||||
.setInputData(dataWorker.storeInputData(mbgArray))
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
@ -546,7 +546,7 @@ class NSClientService : DaggerService() {
|
|||
sp.putBoolean(R.string.key_ObjectivesbgIsAvailableInNS, true)
|
||||
dataWorker.enqueue(
|
||||
OneTimeWorkRequest.Builder(NSClientSourceWorker::class.java)
|
||||
.setInputData(dataWorker.storeInputData(sgvs, null))
|
||||
.setInputData(dataWorker.storeInputData(sgvs))
|
||||
.build()
|
||||
)
|
||||
xDripBroadcast.sendSgvs(sgvs)
|
||||
|
|
|
@ -1,44 +1,42 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview
|
||||
|
||||
import android.graphics.DashPathEffect
|
||||
import android.graphics.Paint
|
||||
import android.content.Context
|
||||
import androidx.annotation.ColorInt
|
||||
import com.jjoe64.graphview.series.BarGraphSeries
|
||||
import com.jjoe64.graphview.series.DataPoint
|
||||
import com.jjoe64.graphview.series.LineGraphSeries
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.data.IobTotal
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.extensions.*
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||
import info.nightscout.androidaps.extensions.convertedToPercent
|
||||
import info.nightscout.androidaps.extensions.isInProgress
|
||||
import info.nightscout.androidaps.extensions.toStringFull
|
||||
import info.nightscout.androidaps.extensions.toStringShort
|
||||
import info.nightscout.androidaps.extensions.valueToUnits
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.FixedLineGraphSeries
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@Singleton
|
||||
class OverviewData @Inject constructor(
|
||||
private val injector: HasAndroidInjector,
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val rh: ResourceHelper,
|
||||
private val dateUtil: DateUtil,
|
||||
|
@ -46,13 +44,7 @@ class OverviewData @Inject constructor(
|
|||
private val activePlugin: ActivePlugin,
|
||||
private val defaultValueHelper: DefaultValueHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val config: Config,
|
||||
private val loop: Loop,
|
||||
private val nsDeviceStatus: NSDeviceStatus,
|
||||
private val repository: AppRepository,
|
||||
private val overviewMenus: OverviewMenus,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val translator: Translator
|
||||
private val repository: AppRepository
|
||||
) {
|
||||
|
||||
var rangeToDisplay = 6 // for graph
|
||||
|
@ -62,14 +54,7 @@ class OverviewData @Inject constructor(
|
|||
|
||||
fun reset() {
|
||||
pumpStatus = ""
|
||||
calcProgress = ""
|
||||
lastBg = null
|
||||
bolusIob = null
|
||||
basalIob = null
|
||||
cobInfo = null
|
||||
lastCarbsTime = 0L
|
||||
temporaryTarget = null
|
||||
lastAutosensData = null
|
||||
calcProgressPct = 100
|
||||
bgReadingsArray = ArrayList()
|
||||
bucketedGraphSeries = PointsWithLabelGraphSeries()
|
||||
bgReadingGraphSeries = PointsWithLabelGraphSeries()
|
||||
|
@ -120,13 +105,18 @@ class OverviewData @Inject constructor(
|
|||
* CALC PROGRESS
|
||||
*/
|
||||
|
||||
var calcProgress: String = ""
|
||||
var calcProgressPct: Int = 100
|
||||
|
||||
/*
|
||||
* BG
|
||||
*/
|
||||
|
||||
var lastBg: GlucoseValue? = null
|
||||
val lastBg: GlucoseValue?
|
||||
get() =
|
||||
repository.getLastGlucoseValueWrapped().blockingGet().let { gvWrapped ->
|
||||
if (gvWrapped is ValueWrapper.Existing) gvWrapped.value
|
||||
else null
|
||||
}
|
||||
|
||||
val isLow: Boolean
|
||||
get() = lastBg?.let { lastBg ->
|
||||
|
@ -138,11 +128,12 @@ class OverviewData @Inject constructor(
|
|||
lastBg.valueToUnits(profileFunction.getUnits()) > defaultValueHelper.determineHighLine()
|
||||
} ?: false
|
||||
|
||||
val lastBgColor: Int
|
||||
get() = when {
|
||||
isLow -> rh.gc(R.color.low)
|
||||
isHigh -> rh.gc(R.color.high)
|
||||
else -> rh.gc(R.color.inrange)
|
||||
@ColorInt
|
||||
fun lastBgColor(context: Context?): Int =
|
||||
when {
|
||||
isLow -> rh.gac(context, R.attr.bgLow)
|
||||
isHigh -> rh.gac(context, R.attr.highColor)
|
||||
else -> rh.gac(context, R.attr.bgInRange)
|
||||
}
|
||||
|
||||
val lastBgDescription: String
|
||||
|
@ -162,17 +153,16 @@ class OverviewData @Inject constructor(
|
|||
* TEMPORARY BASAL
|
||||
*/
|
||||
|
||||
val temporaryBasalText: String
|
||||
get() =
|
||||
profileFunction.getProfile()?.let { profile ->
|
||||
var temporaryBasal = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())
|
||||
if (temporaryBasal?.isInProgress == false) temporaryBasal = null
|
||||
temporaryBasal?.let { "T:" + it.toStringShort() }
|
||||
?: rh.gs(R.string.pump_basebasalrate, profile.getBasal())
|
||||
} ?: rh.gs(R.string.notavailable)
|
||||
fun temporaryBasalText(iobCobCalculator: IobCobCalculator): String =
|
||||
profileFunction.getProfile()?.let { profile ->
|
||||
var temporaryBasal = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())
|
||||
if (temporaryBasal?.isInProgress == false) temporaryBasal = null
|
||||
temporaryBasal?.let { "T:" + it.toStringShort() }
|
||||
?: rh.gs(R.string.pump_basebasalrate, profile.getBasal())
|
||||
} ?: rh.gs(R.string.notavailable)
|
||||
|
||||
val temporaryBasalDialogText: String
|
||||
get() = profileFunction.getProfile()?.let { profile ->
|
||||
fun temporaryBasalDialogText(iobCobCalculator: IobCobCalculator): String =
|
||||
profileFunction.getProfile()?.let { profile ->
|
||||
iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { temporaryBasal ->
|
||||
"${rh.gs(R.string.basebasalrate_label)}: ${rh.gs(R.string.pump_basebasalrate, profile.getBasal())}" +
|
||||
"\n" + rh.gs(R.string.tempbasal_label) + ": " + temporaryBasal.toStringFull(profile, dateUtil)
|
||||
|
@ -180,76 +170,73 @@ class OverviewData @Inject constructor(
|
|||
?: "${rh.gs(R.string.basebasalrate_label)}: ${rh.gs(R.string.pump_basebasalrate, profile.getBasal())}"
|
||||
} ?: rh.gs(R.string.notavailable)
|
||||
|
||||
val temporaryBasalIcon: Int
|
||||
get() =
|
||||
profileFunction.getProfile()?.let { profile ->
|
||||
iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { temporaryBasal ->
|
||||
val percentRate = temporaryBasal.convertedToPercent(dateUtil.now(), profile)
|
||||
when {
|
||||
percentRate > 100 -> R.drawable.ic_cp_basal_tbr_high
|
||||
percentRate < 100 -> R.drawable.ic_cp_basal_tbr_low
|
||||
else -> R.drawable.ic_cp_basal_no_tbr
|
||||
}
|
||||
fun temporaryBasalIcon(iobCobCalculator: IobCobCalculator): Int =
|
||||
profileFunction.getProfile()?.let { profile ->
|
||||
iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { temporaryBasal ->
|
||||
val percentRate = temporaryBasal.convertedToPercent(dateUtil.now(), profile)
|
||||
when {
|
||||
percentRate > 100 -> R.drawable.ic_cp_basal_tbr_high
|
||||
percentRate < 100 -> R.drawable.ic_cp_basal_tbr_low
|
||||
else -> R.drawable.ic_cp_basal_no_tbr
|
||||
}
|
||||
} ?: R.drawable.ic_cp_basal_no_tbr
|
||||
}
|
||||
} ?: R.drawable.ic_cp_basal_no_tbr
|
||||
|
||||
val temporaryBasalColor: Int
|
||||
get() = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { rh.gc(R.color.basal) }
|
||||
?: rh.gc(R.color.defaulttextcolor)
|
||||
fun temporaryBasalColor(context: Context?, iobCobCalculator: IobCobCalculator): Int = iobCobCalculator.getTempBasalIncludingConvertedExtended(dateUtil.now())?.let { rh.gac(context , R.attr.basal) }
|
||||
?: rh.gac(context, R.attr.defaultTextColor)
|
||||
|
||||
/*
|
||||
* EXTENDED BOLUS
|
||||
*/
|
||||
|
||||
val extendedBolusText: String
|
||||
get() =
|
||||
iobCobCalculator.getExtendedBolus(dateUtil.now())?.let { extendedBolus ->
|
||||
if (!extendedBolus.isInProgress(dateUtil)) ""
|
||||
else if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) rh.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
||||
else ""
|
||||
} ?: ""
|
||||
fun extendedBolusText(iobCobCalculator: IobCobCalculator): String =
|
||||
iobCobCalculator.getExtendedBolus(dateUtil.now())?.let { extendedBolus ->
|
||||
if (!extendedBolus.isInProgress(dateUtil)) ""
|
||||
else if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) rh.gs(R.string.pump_basebasalrate, extendedBolus.rate)
|
||||
else ""
|
||||
} ?: ""
|
||||
|
||||
val extendedBolusDialogText: String
|
||||
get() = iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil) ?: ""
|
||||
fun extendedBolusDialogText(iobCobCalculator: IobCobCalculator): String =
|
||||
iobCobCalculator.getExtendedBolus(dateUtil.now())?.toStringFull(dateUtil) ?: ""
|
||||
|
||||
/*
|
||||
* IOB, COB
|
||||
*/
|
||||
|
||||
var bolusIob: IobTotal? = null
|
||||
var basalIob: IobTotal? = null
|
||||
var cobInfo: CobInfo? = null
|
||||
var lastCarbsTime: Long = 0L
|
||||
fun bolusIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromBolus().round()
|
||||
fun basalIob(iobCobCalculator: IobCobCalculator): IobTotal = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
|
||||
fun cobInfo(iobCobCalculator: IobCobCalculator): CobInfo = iobCobCalculator.getCobInfo(true, "Overview COB")
|
||||
|
||||
val iobText: String
|
||||
get() =
|
||||
bolusIob?.let { bolusIob ->
|
||||
basalIob?.let { basalIob ->
|
||||
rh.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
|
||||
} ?: rh.gs(R.string.value_unavailable_short)
|
||||
} ?: rh.gs(R.string.value_unavailable_short)
|
||||
val lastCarbsTime: Long
|
||||
get() = repository.getLastCarbsRecordWrapped().blockingGet().let { lastCarbs ->
|
||||
if (lastCarbs is ValueWrapper.Existing) lastCarbs.value.timestamp else 0L
|
||||
}
|
||||
|
||||
val iobDialogText: String
|
||||
get() =
|
||||
bolusIob?.let { bolusIob ->
|
||||
basalIob?.let { basalIob ->
|
||||
rh.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" +
|
||||
rh.gs(R.string.bolus) + ": " + rh.gs(R.string.formatinsulinunits, bolusIob.iob) + "\n" +
|
||||
rh.gs(R.string.basal) + ": " + rh.gs(R.string.formatinsulinunits, basalIob.basaliob)
|
||||
} ?: rh.gs(R.string.value_unavailable_short)
|
||||
} ?: rh.gs(R.string.value_unavailable_short)
|
||||
fun iobText(iobCobCalculator: IobCobCalculator): String =
|
||||
rh.gs(R.string.formatinsulinunits, bolusIob(iobCobCalculator).iob + basalIob(iobCobCalculator).basaliob)
|
||||
|
||||
fun iobDialogText(iobCobCalculator: IobCobCalculator): String =
|
||||
rh.gs(R.string.formatinsulinunits, bolusIob(iobCobCalculator).iob + basalIob(iobCobCalculator).basaliob) + "\n" +
|
||||
rh.gs(R.string.bolus) + ": " + rh.gs(R.string.formatinsulinunits, bolusIob(iobCobCalculator).iob) + "\n" +
|
||||
rh.gs(R.string.basal) + ": " + rh.gs(R.string.formatinsulinunits, basalIob(iobCobCalculator).basaliob)
|
||||
|
||||
/*
|
||||
* TEMP TARGET
|
||||
*/
|
||||
|
||||
var temporaryTarget: TemporaryTarget? = null
|
||||
val temporaryTarget: TemporaryTarget?
|
||||
get() =
|
||||
repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet().let { tempTarget ->
|
||||
if (tempTarget is ValueWrapper.Existing) tempTarget.value
|
||||
else null
|
||||
}
|
||||
|
||||
/*
|
||||
* SENSITIVITY
|
||||
*/
|
||||
|
||||
var lastAutosensData: AutosensData? = null
|
||||
fun lastAutosensData(iobCobCalculator: IobCobCalculator) = iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil)
|
||||
|
||||
/*
|
||||
* Graphs
|
||||
*/
|
||||
|
@ -276,6 +263,8 @@ class OverviewData @Inject constructor(
|
|||
|
||||
var maxTreatmentsValue = 0.0
|
||||
var treatmentsSeries: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
var maxTherapyEventValue = 0.0
|
||||
var therapyEventSeries: PointsWithLabelGraphSeries<DataPointWithLabelInterface> = PointsWithLabelGraphSeries()
|
||||
|
||||
var maxIobValueFound = Double.MIN_VALUE
|
||||
val iobScale = Scale()
|
||||
|
@ -309,532 +298,4 @@ class OverviewData @Inject constructor(
|
|||
val dsMinScale = Scale()
|
||||
var dsMaxSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
var dsMinSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
|
||||
@Synchronized
|
||||
@Suppress("SameParameterValue", "UNUSED_PARAMETER")
|
||||
fun prepareBgData(from: String) {
|
||||
// val start = dateUtil.now()
|
||||
maxBgValue = Double.MIN_VALUE
|
||||
bgReadingsArray = repository.compatGetBgReadingsDataFromTime(fromTime, toTime, false).blockingGet()
|
||||
val bgListArray: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||
for (bg in bgReadingsArray) {
|
||||
if (bg.timestamp < fromTime || bg.timestamp > toTime) continue
|
||||
if (bg.value > maxBgValue) maxBgValue = bg.value
|
||||
bgListArray.add(GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh))
|
||||
}
|
||||
bgListArray.sortWith { o1: DataPointWithLabelInterface, o2: DataPointWithLabelInterface -> o1.x.compareTo(o2.x) }
|
||||
bgReadingGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] })
|
||||
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, profileFunction.getUnits())
|
||||
if (defaultValueHelper.determineHighLine() > maxBgValue) maxBgValue = defaultValueHelper.determineHighLine()
|
||||
maxBgValue = addUpperChartMargin(maxBgValue)
|
||||
// profiler.log(LTag.UI, "prepareBgData() $from", start)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Synchronized
|
||||
fun preparePredictions(from: String) {
|
||||
// val start = dateUtil.now()
|
||||
val apsResult = if (config.APS) loop.lastRun?.constraintsProcessed else nsDeviceStatus.getAPSResult(injector)
|
||||
val predictionsAvailable = if (config.APS) loop.lastRun?.request?.hasPredictions == true else config.NSCLIENT
|
||||
val menuChartSettings = overviewMenus.setting
|
||||
// align to hours
|
||||
val calendar = Calendar.getInstance().also {
|
||||
it.timeInMillis = System.currentTimeMillis()
|
||||
it[Calendar.MILLISECOND] = 0
|
||||
it[Calendar.SECOND] = 0
|
||||
it[Calendar.MINUTE] = 0
|
||||
it.add(Calendar.HOUR, 1)
|
||||
}
|
||||
if (predictionsAvailable && apsResult != null && menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal]) {
|
||||
var predictionHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt()
|
||||
predictionHours = min(2, predictionHours)
|
||||
predictionHours = max(0, predictionHours)
|
||||
val hoursToFetch = rangeToDisplay - predictionHours
|
||||
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||
fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs()
|
||||
endTime = toTime + T.hours(predictionHours.toLong()).msecs()
|
||||
} else {
|
||||
toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific
|
||||
fromTime = toTime - T.hours(rangeToDisplay.toLong()).msecs()
|
||||
endTime = toTime
|
||||
}
|
||||
|
||||
val bgListArray: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||
val predictions: MutableList<GlucoseValueDataPoint>? = apsResult?.predictions
|
||||
?.map { bg -> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh) }
|
||||
?.toMutableList()
|
||||
if (predictions != null) {
|
||||
predictions.sortWith { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) }
|
||||
for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction)
|
||||
}
|
||||
predictionsGraphSeries = PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] })
|
||||
// profiler.log(LTag.UI, "preparePredictions() $from", start)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@Suppress("SameParameterValue", "UNUSED_PARAMETER")
|
||||
fun prepareBucketedData(from: String) {
|
||||
// val start = dateUtil.now()
|
||||
val bucketedData = iobCobCalculator.ads.getBucketedDataTableCopy() ?: return
|
||||
if (bucketedData.isEmpty()) {
|
||||
aapsLogger.debug("No bucketed data.")
|
||||
return
|
||||
}
|
||||
val bucketedListArray: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||
for (inMemoryGlucoseValue in bucketedData) {
|
||||
if (inMemoryGlucoseValue.timestamp < fromTime || inMemoryGlucoseValue.timestamp > toTime) continue
|
||||
bucketedListArray.add(InMemoryGlucoseValueDataPoint(inMemoryGlucoseValue, profileFunction, rh))
|
||||
}
|
||||
bucketedListArray.sortWith { o1: DataPointWithLabelInterface, o2: DataPointWithLabelInterface -> o1.x.compareTo(o2.x) }
|
||||
bucketedGraphSeries = PointsWithLabelGraphSeries(Array(bucketedListArray.size) { i -> bucketedListArray[i] })
|
||||
// profiler.log(LTag.UI, "prepareBucketedData() $from", start)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Synchronized
|
||||
fun prepareBasalData(from: String) {
|
||||
// val start = dateUtil.now()
|
||||
maxBasalValueFound = 0.0
|
||||
val baseBasalArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val tempBasalArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val basalLineArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val absoluteBasalLineArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
var lastLineBasal = 0.0
|
||||
var lastAbsoluteLineBasal = -1.0
|
||||
var lastBaseBasal = 0.0
|
||||
var lastTempBasal = 0.0
|
||||
var time = fromTime
|
||||
while (time < toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 60 * 1000L
|
||||
continue
|
||||
}
|
||||
val basalData = iobCobCalculator.getBasalData(profile, time)
|
||||
val baseBasalValue = basalData.basal
|
||||
var absoluteLineValue = baseBasalValue
|
||||
var tempBasalValue = 0.0
|
||||
var basal = 0.0
|
||||
if (basalData.isTempBasalRunning) {
|
||||
tempBasalValue = basalData.tempBasalAbsolute
|
||||
absoluteLineValue = tempBasalValue
|
||||
if (tempBasalValue != lastTempBasal) {
|
||||
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale))
|
||||
tempBasalArray.add(ScaledDataPoint(time, tempBasalValue.also { basal = it }, basalScale))
|
||||
}
|
||||
if (lastBaseBasal != 0.0) {
|
||||
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale))
|
||||
baseBasalArray.add(ScaledDataPoint(time, 0.0, basalScale))
|
||||
lastBaseBasal = 0.0
|
||||
}
|
||||
} else {
|
||||
if (baseBasalValue != lastBaseBasal) {
|
||||
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale))
|
||||
baseBasalArray.add(ScaledDataPoint(time, baseBasalValue.also { basal = it }, basalScale))
|
||||
lastBaseBasal = baseBasalValue
|
||||
}
|
||||
if (lastTempBasal != 0.0) {
|
||||
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale))
|
||||
tempBasalArray.add(ScaledDataPoint(time, 0.0, basalScale))
|
||||
}
|
||||
}
|
||||
if (baseBasalValue != lastLineBasal) {
|
||||
basalLineArray.add(ScaledDataPoint(time, lastLineBasal, basalScale))
|
||||
basalLineArray.add(ScaledDataPoint(time, baseBasalValue, basalScale))
|
||||
}
|
||||
if (absoluteLineValue != lastAbsoluteLineBasal) {
|
||||
absoluteBasalLineArray.add(ScaledDataPoint(time, lastAbsoluteLineBasal, basalScale))
|
||||
absoluteBasalLineArray.add(ScaledDataPoint(time, basal, basalScale))
|
||||
}
|
||||
lastAbsoluteLineBasal = absoluteLineValue
|
||||
lastLineBasal = baseBasalValue
|
||||
lastTempBasal = tempBasalValue
|
||||
maxBasalValueFound = max(maxBasalValueFound, max(tempBasalValue, baseBasalValue))
|
||||
time += 60 * 1000L
|
||||
}
|
||||
|
||||
// final points
|
||||
basalLineArray.add(ScaledDataPoint(toTime, lastLineBasal, basalScale))
|
||||
baseBasalArray.add(ScaledDataPoint(toTime, lastBaseBasal, basalScale))
|
||||
tempBasalArray.add(ScaledDataPoint(toTime, lastTempBasal, basalScale))
|
||||
absoluteBasalLineArray.add(ScaledDataPoint(toTime, lastAbsoluteLineBasal, basalScale))
|
||||
|
||||
// create series
|
||||
baseBasalGraphSeries = LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also {
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = rh.gc(R.color.basebasal)
|
||||
it.thickness = 0
|
||||
}
|
||||
tempBasalGraphSeries = LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also {
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = rh.gc(R.color.tempbasal)
|
||||
it.thickness = 0
|
||||
}
|
||||
basalLineGraphSeries = LineGraphSeries(Array(basalLineArray.size) { i -> basalLineArray[i] }).also {
|
||||
it.setCustomPaint(Paint().also { paint ->
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = rh.getDisplayMetrics().scaledDensity * 2
|
||||
paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f)
|
||||
paint.color = rh.gc(R.color.basal)
|
||||
})
|
||||
}
|
||||
absoluteBasalGraphSeries = LineGraphSeries(Array(absoluteBasalLineArray.size) { i -> absoluteBasalLineArray[i] }).also {
|
||||
it.setCustomPaint(Paint().also { absolutePaint ->
|
||||
absolutePaint.style = Paint.Style.STROKE
|
||||
absolutePaint.strokeWidth = rh.getDisplayMetrics().scaledDensity * 2
|
||||
absolutePaint.color = rh.gc(R.color.basal)
|
||||
})
|
||||
}
|
||||
// profiler.log(LTag.UI, "prepareBasalData() $from", start)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Synchronized
|
||||
fun prepareTemporaryTargetData(from: String) {
|
||||
// val start = dateUtil.now()
|
||||
val profile = profileFunction.getProfile() ?: return
|
||||
val units = profileFunction.getUnits()
|
||||
var toTime = toTime
|
||||
val targetsSeriesArray: MutableList<DataPoint> = java.util.ArrayList()
|
||||
var lastTarget = -1.0
|
||||
loop.lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) }
|
||||
var time = fromTime
|
||||
while (time < toTime) {
|
||||
val tt = repository.getTemporaryTargetActiveAt(time).blockingGet()
|
||||
val value: Double = if (tt is ValueWrapper.Existing) {
|
||||
Profile.fromMgdlToUnits(tt.value.target(), units)
|
||||
} else {
|
||||
Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
|
||||
}
|
||||
if (lastTarget != value) {
|
||||
if (lastTarget != -1.0) targetsSeriesArray.add(DataPoint(time.toDouble(), lastTarget))
|
||||
targetsSeriesArray.add(DataPoint(time.toDouble(), value))
|
||||
}
|
||||
lastTarget = value
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
// final point
|
||||
targetsSeriesArray.add(DataPoint(toTime.toDouble(), lastTarget))
|
||||
// create series
|
||||
temporaryTargetSeries = LineGraphSeries(Array(targetsSeriesArray.size) { i -> targetsSeriesArray[i] }).also {
|
||||
it.isDrawBackground = false
|
||||
it.color = rh.gc(R.color.tempTargetBackground)
|
||||
it.thickness = 2
|
||||
}
|
||||
// profiler.log(LTag.UI, "prepareTemporaryTargetData() $from", start)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Synchronized
|
||||
fun prepareTreatmentsData(from: String) {
|
||||
// val start = dateUtil.now()
|
||||
maxTreatmentsValue = 0.0
|
||||
val filteredTreatments: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||
repository.getBolusesDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||
.map { BolusDataPoint(it, rh, activePlugin, defaultValueHelper) }
|
||||
.filter { it.data.type == Bolus.Type.NORMAL || it.data.type == Bolus.Type.SMB }
|
||||
.forEach {
|
||||
it.y = getNearestBg(it.x.toLong())
|
||||
filteredTreatments.add(it)
|
||||
}
|
||||
repository.getCarbsDataFromTimeToTimeExpanded(fromTime, endTime, true).blockingGet()
|
||||
.map { CarbsDataPoint(it, rh) }
|
||||
.forEach {
|
||||
it.y = getNearestBg(it.x.toLong())
|
||||
filteredTreatments.add(it)
|
||||
}
|
||||
|
||||
// ProfileSwitch
|
||||
repository.getEffectiveProfileSwitchDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||
.map { EffectiveProfileSwitchDataPoint(it) }
|
||||
.forEach(filteredTreatments::add)
|
||||
|
||||
// OfflineEvent
|
||||
repository.getOfflineEventDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||
.map {
|
||||
TherapyEventDataPoint(
|
||||
TherapyEvent(timestamp = it.timestamp, duration = it.duration, type = TherapyEvent.Type.APS_OFFLINE, glucoseUnit = TherapyEvent.GlucoseUnit.MMOL),
|
||||
rh,
|
||||
profileFunction,
|
||||
translator
|
||||
)
|
||||
}
|
||||
.forEach(filteredTreatments::add)
|
||||
|
||||
// Extended bolus
|
||||
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
|
||||
repository.getExtendedBolusDataFromTimeToTime(fromTime, endTime, true).blockingGet()
|
||||
.map { ExtendedBolusDataPoint(it) }
|
||||
.filter { it.duration != 0L }
|
||||
.forEach {
|
||||
it.y = getNearestBg(it.x.toLong())
|
||||
filteredTreatments.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
// Careportal
|
||||
repository.compatGetTherapyEventDataFromToTime(fromTime - T.hours(6).msecs(), endTime).blockingGet()
|
||||
.map { TherapyEventDataPoint(it, rh, profileFunction, translator) }
|
||||
.filterTimeframe(fromTime, endTime)
|
||||
.forEach {
|
||||
if (it.y == 0.0) it.y = getNearestBg(it.x.toLong())
|
||||
filteredTreatments.add(it)
|
||||
}
|
||||
|
||||
// increase maxY if a treatment forces it's own height that's higher than a BG value
|
||||
filteredTreatments.map { it.y }
|
||||
.maxOrNull()
|
||||
?.let(::addUpperChartMargin)
|
||||
?.let { maxTreatmentsValue = maxOf(maxTreatmentsValue, it) }
|
||||
|
||||
treatmentsSeries = PointsWithLabelGraphSeries(filteredTreatments.toTypedArray())
|
||||
// profiler.log(LTag.UI, "prepareTreatmentsData() $from", start)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Synchronized
|
||||
fun prepareIobAutosensData(from: String) {
|
||||
// val start = dateUtil.now()
|
||||
val iobArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val absIobArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
maxIobValueFound = Double.MIN_VALUE
|
||||
var lastIob = 0.0
|
||||
var absLastIob = 0.0
|
||||
var time = fromTime
|
||||
|
||||
val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||
val cobArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
maxCobValueFound = Double.MIN_VALUE
|
||||
var lastCob = 0
|
||||
|
||||
val actArrayHist: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val actArrayPrediction: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val now = dateUtil.now().toDouble()
|
||||
maxIAValue = 0.0
|
||||
|
||||
val bgiArrayHist: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val bgiArrayPrediction: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
maxBGIValue = Double.MIN_VALUE
|
||||
|
||||
val devArray: MutableList<OverviewPlugin.DeviationDataPoint> = java.util.ArrayList()
|
||||
maxDevValueFound = Double.MIN_VALUE
|
||||
|
||||
val ratioArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
maxRatioValueFound = 5.0 //even if sens data equals 0 for all the period, minimum scale is between 95% and 105%
|
||||
minRatioValueFound = -5.0
|
||||
|
||||
val dsMaxArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
val dsMinArray: MutableList<ScaledDataPoint> = java.util.ArrayList()
|
||||
maxFromMaxValueFound = Double.MIN_VALUE
|
||||
maxFromMinValueFound = Double.MIN_VALUE
|
||||
|
||||
val adsData = iobCobCalculator.ads.clone()
|
||||
|
||||
while (time <= toTime) {
|
||||
val profile = profileFunction.getProfile(time)
|
||||
if (profile == null) {
|
||||
time += 5 * 60 * 1000L
|
||||
continue
|
||||
}
|
||||
// IOB
|
||||
val iob = iobCobCalculator.calculateFromTreatmentsAndTemps(time, profile)
|
||||
val baseBasalIob = iobCobCalculator.calculateAbsoluteIobFromBaseBasals(time)
|
||||
val absIob = IobTotal.combine(iob, baseBasalIob)
|
||||
val autosensData = adsData.getAutosensDataAtTime(time)
|
||||
if (abs(lastIob - iob.iob) > 0.02) {
|
||||
if (abs(lastIob - iob.iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||
iobArray.add(ScaledDataPoint(time, iob.iob, iobScale))
|
||||
maxIobValueFound = maxOf(maxIobValueFound, abs(iob.iob))
|
||||
lastIob = iob.iob
|
||||
}
|
||||
if (abs(absLastIob - absIob.iob) > 0.02) {
|
||||
if (abs(absLastIob - absIob.iob) > 0.2) absIobArray.add(ScaledDataPoint(time, absLastIob, iobScale))
|
||||
absIobArray.add(ScaledDataPoint(time, absIob.iob, iobScale))
|
||||
maxIobValueFound = maxOf(maxIobValueFound, abs(absIob.iob))
|
||||
absLastIob = absIob.iob
|
||||
}
|
||||
|
||||
// COB
|
||||
if (autosensData != null) {
|
||||
val cob = autosensData.cob.toInt()
|
||||
if (cob != lastCob) {
|
||||
if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), cobScale))
|
||||
cobArray.add(ScaledDataPoint(time, cob.toDouble(), cobScale))
|
||||
maxCobValueFound = max(maxCobValueFound, cob.toDouble())
|
||||
lastCob = cob
|
||||
}
|
||||
if (autosensData.failOverToMinAbsorptionRate) {
|
||||
autosensData.scale = cobScale
|
||||
autosensData.chartTime = time
|
||||
minFailOverActiveList.add(autosensData)
|
||||
}
|
||||
}
|
||||
|
||||
// ACTIVITY
|
||||
if (time <= now) actArrayHist.add(ScaledDataPoint(time, iob.activity, actScale))
|
||||
else actArrayPrediction.add(ScaledDataPoint(time, iob.activity, actScale))
|
||||
maxIAValue = max(maxIAValue, abs(iob.activity))
|
||||
|
||||
// BGI
|
||||
val devBgiScale = overviewMenus.isEnabledIn(OverviewMenus.CharType.DEV) == overviewMenus.isEnabledIn(OverviewMenus.CharType.BGI)
|
||||
val deviation = if (devBgiScale) autosensData?.deviation ?: 0.0 else 0.0
|
||||
val bgi: Double = iob.activity * profile.getIsfMgdl(time) * 5.0
|
||||
if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale))
|
||||
else bgiArrayPrediction.add(ScaledDataPoint(time, bgi, bgiScale))
|
||||
maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation))
|
||||
|
||||
// DEVIATIONS
|
||||
if (autosensData != null) {
|
||||
var color = rh.gc(R.color.deviationblack) // "="
|
||||
if (autosensData.type == "" || autosensData.type == "non-meal") {
|
||||
if (autosensData.pastSensitivity == "C") color = rh.gc(R.color.deviationgrey)
|
||||
if (autosensData.pastSensitivity == "+") color = rh.gc(R.color.deviationgreen)
|
||||
if (autosensData.pastSensitivity == "-") color = rh.gc(R.color.deviationred)
|
||||
} else if (autosensData.type == "uam") {
|
||||
color = rh.gc(R.color.uam)
|
||||
} else if (autosensData.type == "csf") {
|
||||
color = rh.gc(R.color.deviationgrey)
|
||||
}
|
||||
devArray.add(OverviewPlugin.DeviationDataPoint(time.toDouble(), autosensData.deviation, color, devScale))
|
||||
maxDevValueFound = maxOf(maxDevValueFound, abs(autosensData.deviation), abs(bgi))
|
||||
}
|
||||
|
||||
// RATIO
|
||||
if (autosensData != null) {
|
||||
ratioArray.add(ScaledDataPoint(time, 100.0 * (autosensData.autosensResult.ratio - 1), ratioScale))
|
||||
maxRatioValueFound = max(maxRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1))
|
||||
minRatioValueFound = min(minRatioValueFound, 100.0 * (autosensData.autosensResult.ratio - 1))
|
||||
}
|
||||
|
||||
// DEV SLOPE
|
||||
if (autosensData != null) {
|
||||
dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale))
|
||||
dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale))
|
||||
maxFromMaxValueFound = max(maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation))
|
||||
maxFromMinValueFound = max(maxFromMinValueFound, abs(autosensData.slopeFromMinDeviation))
|
||||
}
|
||||
|
||||
time += 5 * 60 * 1000L
|
||||
}
|
||||
// IOB
|
||||
iobSeries = FixedLineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also {
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = -0x7f000001 and rh.gc(R.color.iob) //50%
|
||||
it.color = rh.gc(R.color.iob)
|
||||
it.thickness = 3
|
||||
}
|
||||
absIobSeries = FixedLineGraphSeries(Array(absIobArray.size) { i -> absIobArray[i] }).also {
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = -0x7f000001 and rh.gc(R.color.iob) //50%
|
||||
it.color = rh.gc(R.color.iob)
|
||||
it.thickness = 3
|
||||
}
|
||||
|
||||
if (overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal]) {
|
||||
val autosensData = adsData.getLastAutosensData("GraphData", aapsLogger, dateUtil)
|
||||
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
|
||||
val isTempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet() is ValueWrapper.Existing
|
||||
val iobPrediction: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||
val iobPredictionArray = iobCobCalculator.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||
for (i in iobPredictionArray) {
|
||||
iobPrediction.add(i.setColor(rh.gc(R.color.iobPredAS)))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||
}
|
||||
iobPredictions1Series = PointsWithLabelGraphSeries(Array(iobPrediction.size) { i -> iobPrediction[i] })
|
||||
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray))
|
||||
/*
|
||||
val iobPrediction2: MutableList<DataPointWithLabelInterface> = java.util.ArrayList()
|
||||
val iobPredictionArray2 = iobCobCalculator.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||
for (i in iobPredictionArray2) {
|
||||
iobPrediction2.add(i.setColor(rh.gc(R.color.iobPred)))
|
||||
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||
}
|
||||
iobPredictions2Series = PointsWithLabelGraphSeries(Array(iobPrediction2.size) { i -> iobPrediction2[i] })
|
||||
aapsLogger.debug(LTag.AUTOSENS, "IOB prediction for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculator.iobArrayToString(iobPredictionArray2))
|
||||
*/
|
||||
} else {
|
||||
iobPredictions1Series = PointsWithLabelGraphSeries()
|
||||
//iobPredictions2Series = PointsWithLabelGraphSeries()
|
||||
}
|
||||
|
||||
// COB
|
||||
cobSeries = FixedLineGraphSeries(Array(cobArray.size) { i -> cobArray[i] }).also {
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = -0x7f000001 and rh.gc(R.color.cob) //50%
|
||||
it.color = rh.gc(R.color.cob)
|
||||
it.thickness = 3
|
||||
}
|
||||
cobMinFailOverSeries = PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] })
|
||||
|
||||
// ACTIVITY
|
||||
activitySeries = FixedLineGraphSeries(Array(actArrayHist.size) { i -> actArrayHist[i] }).also {
|
||||
it.isDrawBackground = false
|
||||
it.color = rh.gc(R.color.activity)
|
||||
it.thickness = 3
|
||||
}
|
||||
activityPredictionSeries = FixedLineGraphSeries(Array(actArrayPrediction.size) { i -> actArrayPrediction[i] }).also {
|
||||
it.setCustomPaint(Paint().also { paint ->
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = 3f
|
||||
paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
|
||||
paint.color = rh.gc(R.color.activity)
|
||||
})
|
||||
}
|
||||
|
||||
// BGI
|
||||
minusBgiSeries = FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also {
|
||||
it.isDrawBackground = false
|
||||
it.color = rh.gc(R.color.bgi)
|
||||
it.thickness = 3
|
||||
}
|
||||
minusBgiHistSeries = FixedLineGraphSeries(Array(bgiArrayPrediction.size) { i -> bgiArrayPrediction[i] }).also {
|
||||
it.setCustomPaint(Paint().also { paint ->
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = 3f
|
||||
paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
|
||||
paint.color = rh.gc(R.color.bgi)
|
||||
})
|
||||
}
|
||||
|
||||
// DEVIATIONS
|
||||
deviationsSeries = BarGraphSeries(Array(devArray.size) { i -> devArray[i] }).also {
|
||||
it.setValueDependentColor { data: OverviewPlugin.DeviationDataPoint -> data.color }
|
||||
}
|
||||
|
||||
// RATIO
|
||||
ratioSeries = LineGraphSeries(Array(ratioArray.size) { i -> ratioArray[i] }).also {
|
||||
it.color = rh.gc(R.color.ratio)
|
||||
it.thickness = 3
|
||||
}
|
||||
|
||||
// DEV SLOPE
|
||||
dsMaxSeries = LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also {
|
||||
it.color = rh.gc(R.color.devslopepos)
|
||||
it.thickness = 3
|
||||
}
|
||||
dsMinSeries = LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also {
|
||||
it.color = rh.gc(R.color.devslopeneg)
|
||||
it.thickness = 3
|
||||
}
|
||||
|
||||
// profiler.log(LTag.UI, "prepareIobAutosensData() $from", start)
|
||||
}
|
||||
|
||||
private fun addUpperChartMargin(maxBgValue: Double) =
|
||||
if (profileFunction.getUnits() == GlucoseUnit.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4
|
||||
|
||||
private fun getNearestBg(date: Long): Double {
|
||||
bgReadingsArray.let { bgReadingsArray ->
|
||||
for (reading in bgReadingsArray) {
|
||||
if (reading.timestamp > date) continue
|
||||
return Profile.fromMgdlToUnits(reading.value, profileFunction.getUnits())
|
||||
}
|
||||
return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, profileFunction.getUnits())
|
||||
else Profile.fromMgdlToUnits(100.0, profileFunction.getUnits())
|
||||
}
|
||||
}
|
||||
|
||||
private fun <E : DataPointWithLabelInterface> List<E>.filterTimeframe(fromTime: Long, endTime: Long): List<E> =
|
||||
filter { it.x + it.duration >= fromTime && it.x <= endTime }
|
||||
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@ import android.app.NotificationManager
|
|||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.drawable.AnimationDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
@ -35,17 +36,12 @@ import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
|||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.databinding.OverviewFragmentBinding
|
||||
import info.nightscout.androidaps.dialogs.*
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.extensions.directionToIcon
|
||||
import info.nightscout.androidaps.extensions.isInProgress
|
||||
import info.nightscout.androidaps.extensions.runOnUiThread
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||
|
@ -61,6 +57,7 @@ import info.nightscout.androidaps.plugins.general.overview.notifications.Notific
|
|||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
|
||||
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
||||
import info.nightscout.androidaps.plugins.source.XdripPlugin
|
||||
import info.nightscout.androidaps.skins.SkinProvider
|
||||
|
@ -74,16 +71,16 @@ import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
|||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.androidaps.utils.ui.SingleClickButton
|
||||
import info.nightscout.androidaps.utils.ui.UIRunnable
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
|
||||
|
@ -150,10 +147,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
_binding = it
|
||||
//check screen width
|
||||
dm = DisplayMetrics()
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
|
||||
@Suppress("DEPRECATION")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
|
||||
activity?.display?.getRealMetrics(dm)
|
||||
else
|
||||
@Suppress("DEPRECATION") activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
||||
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
|
||||
}.root
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
@ -166,13 +164,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
|
||||
val landscape = screenHeight < screenWidth
|
||||
|
||||
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, view, landscape, rh.gb(R.bool.isTablet), smallHeight)
|
||||
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, binding, landscape, rh.gb(R.bool.isTablet), smallHeight)
|
||||
binding.nsclientLayout.visibility = config.NSCLIENT.toVisibility()
|
||||
|
||||
binding.notifications.setHasFixedSize(false)
|
||||
binding.notifications.layoutManager = LinearLayoutManager(view.context)
|
||||
axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
|
||||
binding.graphsLayout.bgGraph.gridLabelRenderer?.gridColor = rh.gc(R.color.graphgrid)
|
||||
binding.graphsLayout.bgGraph.gridLabelRenderer?.gridColor = rh.gac(context, R.attr.graphgrid)
|
||||
binding.graphsLayout.bgGraph.gridLabelRenderer?.reloadStyles()
|
||||
binding.graphsLayout.bgGraph.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||
binding.graphsLayout.bgGraph.layoutParams?.height = rh.dpToPx(skinProvider.activeSkin().mainGraphHeight)
|
||||
|
@ -186,16 +184,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
overviewData.rangeToDisplay += 6
|
||||
overviewData.rangeToDisplay = if (overviewData.rangeToDisplay > 24) 6 else overviewData.rangeToDisplay
|
||||
sp.putInt(R.string.key_rangetodisplay, overviewData.rangeToDisplay)
|
||||
overviewData.initRange()
|
||||
overviewData.prepareBucketedData("EventBucketedDataCreated")
|
||||
overviewData.prepareBgData("EventBucketedDataCreated")
|
||||
updateGraph("rangeChange")
|
||||
rxBus.send(EventPreferenceChange(rh, R.string.key_rangetodisplay))
|
||||
sp.putBoolean(R.string.key_objectiveusescale, true)
|
||||
false
|
||||
}
|
||||
prepareGraphsIfNeeded(overviewMenus.setting.size)
|
||||
overviewMenus.setupChartMenu(binding.graphsLayout.chartMenuButton)
|
||||
context?.let { overviewMenus.setupChartMenu(it, binding.graphsLayout.chartMenuButton) }
|
||||
|
||||
binding.activeProfile.setOnClickListener(this)
|
||||
binding.activeProfile.setOnLongClickListener(this)
|
||||
|
@ -225,113 +219,107 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewTime::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateTime(it.from) }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewCalcProgress::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateCalcProgress(it.from) }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewProfile::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateProfile(it.from) }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewTemporaryBasal::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateTemporaryBasal(it.from) }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewExtendedBolus::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateExtendedBolus(it.from) }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewTemporaryTarget::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateTemporaryTarget(it.from) }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewBg::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateBg(it.from) }, fabricPrivacy::logException)
|
||||
.subscribe({ updateCalcProgress() }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewIobCob::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateIobCob(it.from) }, fabricPrivacy::logException)
|
||||
.subscribe({ updateIobCob() }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewSensitivity::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateSensitivity(it.from) }, fabricPrivacy::logException)
|
||||
.subscribe({ updateSensitivity() }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewGraph::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGraph(it.from) }, fabricPrivacy::logException)
|
||||
.subscribe({ updateGraph() }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewPumpStatus::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updatePumpStatus(it.from) }, fabricPrivacy::logException)
|
||||
.subscribe({ updatePumpStatus() }, fabricPrivacy::logException)
|
||||
disposable += activePlugin.activeOverview.overviewBus
|
||||
.toObservable(EventUpdateOverviewNotification::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateNotification(it.from) }, fabricPrivacy::logException)
|
||||
.subscribe({ updateNotification() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventNewBG::class.java)
|
||||
.debounce(1L, TimeUnit.SECONDS)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateBg() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventRefreshOverview::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
if (it.now) overviewPlugin.refreshLoop(it.from)
|
||||
else scheduleUpdateGUI(it.from)
|
||||
if (it.now) refreshAll()
|
||||
else scheduleUpdateGUI()
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAcceptOpenLoopChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventInitializationChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateTime("EventInitializationChanged") }, fabricPrivacy::logException)
|
||||
.subscribe({ scheduleUpdateGUI() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventPreferenceChange") }, fabricPrivacy::logException)
|
||||
.subscribe({ scheduleUpdateGUI() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventNewOpenLoopNotification::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }, fabricPrivacy::logException)
|
||||
.subscribe({ scheduleUpdateGUI() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventPumpStatusChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.delay(30, TimeUnit.MILLISECONDS, aapsSchedulers.main)
|
||||
.subscribe({
|
||||
overviewData.pumpStatus = it.getStatus(rh)
|
||||
updatePumpStatus("EventPumpStatusChanged")
|
||||
updatePumpStatus()
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateProfile() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempTargetChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateTemporaryTarget() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateExtendedBolus() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateTemporaryBasal() }, fabricPrivacy::logException)
|
||||
|
||||
refreshLoop = Runnable {
|
||||
overviewPlugin.refreshLoop("refreshLoop")
|
||||
refreshAll()
|
||||
handler.postDelayed(refreshLoop, 60 * 1000L)
|
||||
}
|
||||
handler.postDelayed(refreshLoop, 60 * 1000L)
|
||||
|
||||
updateTime("onResume")
|
||||
updateCalcProgress("onResume")
|
||||
updateProfile("onResume")
|
||||
updateTemporaryBasal("onResume")
|
||||
updateExtendedBolus("onResume")
|
||||
updateTemporaryTarget("onResume")
|
||||
updateBg("onResume")
|
||||
updateIobCob("onResume")
|
||||
updateSensitivity("onResume")
|
||||
updateGraph("onResume")
|
||||
updatePumpStatus("onResume")
|
||||
updateNotification("onResume")
|
||||
refreshAll()
|
||||
updatePumpStatus()
|
||||
updateCalcProgress()
|
||||
}
|
||||
|
||||
fun refreshAll() {
|
||||
runOnUiThread {
|
||||
_binding ?: return@runOnUiThread
|
||||
updateBg()
|
||||
updateTime()
|
||||
updateProfile()
|
||||
updateTemporaryBasal()
|
||||
updateExtendedBolus()
|
||||
updateTemporaryTarget()
|
||||
updateIobCob()
|
||||
updateSensitivity()
|
||||
updateGraph()
|
||||
updateNotification()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -415,14 +403,15 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
loop.invoke("Accept temp button", false)
|
||||
if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed?.isChangeRequested == true) {
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
|
||||
?: "".toSpanned(), {
|
||||
uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
|
||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?)?.cancel(Constants.notificationID)
|
||||
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
|
||||
Thread { loop.acceptChangeRequest() }.run()
|
||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||
})
|
||||
if (isAdded)
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
|
||||
?: "".toSpanned(), {
|
||||
uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
|
||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?)?.cancel(Constants.notificationID)
|
||||
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
|
||||
Thread { loop.acceptChangeRequest() }.run()
|
||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -558,10 +547,18 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
binding.buttonsLayout.calibrationButton.visibility = (xDripIsBgSource && actualBG != null && sp.getBoolean(R.string.key_show_calibration_button, true)).toVisibility()
|
||||
if (dexcomIsSource) {
|
||||
binding.buttonsLayout.cgmButton.setCompoundDrawablesWithIntrinsicBounds(null, rh.gd(R.drawable.ic_byoda), null, null)
|
||||
binding.buttonsLayout.cgmButton.setTextColor(rh.gc(R.color.colorLightGray))
|
||||
for (drawable in binding.buttonsLayout.cgmButton.compoundDrawables) {
|
||||
drawable?.mutate()
|
||||
drawable?.colorFilter = PorterDuffColorFilter(rh.gac(context, R.attr.cgmdexColor), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
binding.buttonsLayout.cgmButton.setTextColor(rh.gac(context, R.attr.cgmdexColor))
|
||||
} else if (xDripIsBgSource) {
|
||||
binding.buttonsLayout.cgmButton.setCompoundDrawablesWithIntrinsicBounds(null, rh.gd(R.drawable.ic_xdrip), null, null)
|
||||
binding.buttonsLayout.cgmButton.setTextColor(rh.gc(R.color.colorCalibrationButton))
|
||||
for (drawable in binding.buttonsLayout.cgmButton.compoundDrawables) {
|
||||
drawable?.mutate()
|
||||
drawable?.colorFilter = PorterDuffColorFilter(rh.gac(context, R.attr.cgmxdripColor), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
binding.buttonsLayout.cgmButton.setTextColor(rh.gac(context, R.attr.cgmxdripColor))
|
||||
}
|
||||
binding.buttonsLayout.cgmButton.visibility = (sp.getBoolean(R.string.key_show_cgm_button, false) && (xDripIsBgSource || dexcomIsSource)).toVisibility()
|
||||
|
||||
|
@ -573,7 +570,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
if (event.isEnabled && event.trigger.shouldRun())
|
||||
context?.let { context ->
|
||||
SingleClickButton(context).also {
|
||||
it.setTextColor(rh.gc(R.color.colorTreatmentButton))
|
||||
it.setTextColor(rh.gac(context, R.attr.treatmentButton))
|
||||
it.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10f)
|
||||
it.layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 0.5f).also { l ->
|
||||
l.setMargins(0, 0, rh.dpToPx(-4), 0)
|
||||
|
@ -582,11 +579,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
it.text = event.title
|
||||
|
||||
it.setOnClickListener {
|
||||
OKDialog.showConfirmation(
|
||||
context,
|
||||
rh.gs(R.string.run_question, event.title),
|
||||
{ handler.post { automationPlugin.processEvent(event) } }
|
||||
)
|
||||
OKDialog.showConfirmation(context, rh.gs(R.string.run_question, event.title), { handler.post { automationPlugin.processEvent(event) } })
|
||||
}
|
||||
binding.buttonsLayout.userButtonsLayout.addView(it)
|
||||
}
|
||||
|
@ -721,12 +714,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
val graph = GraphView(context)
|
||||
graph.layoutParams =
|
||||
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, rh.dpToPx(skinProvider.activeSkin().secondaryGraphHeight)).also { it.setMargins(0, rh.dpToPx(15), 0, rh.dpToPx(10)) }
|
||||
graph.gridLabelRenderer?.gridColor = rh.gc(R.color.graphgrid)
|
||||
graph.gridLabelRenderer?.gridColor = rh.gac(context, R.attr.graphgrid)
|
||||
graph.gridLabelRenderer?.reloadStyles()
|
||||
graph.gridLabelRenderer?.isHorizontalLabelsVisible = false
|
||||
graph.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||
graph.gridLabelRenderer?.numVerticalLabels = 3
|
||||
graph.viewport.backgroundColor = Color.argb(20, 255, 255, 255) // 8% of gray
|
||||
graph.viewport.backgroundColor = rh.gac(context, R.attr.viewPortbackgroundColor)
|
||||
relativeLayout.addView(graph)
|
||||
|
||||
val label = TextView(context)
|
||||
|
@ -745,11 +738,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
var task: Runnable? = null
|
||||
|
||||
private fun scheduleUpdateGUI(from: String) {
|
||||
private fun scheduleUpdateGUI() {
|
||||
class UpdateRunnable : Runnable {
|
||||
|
||||
override fun run() {
|
||||
overviewPlugin.refreshLoop(from)
|
||||
refreshAll()
|
||||
task = null
|
||||
}
|
||||
}
|
||||
|
@ -759,20 +752,20 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateBg(from: String) {
|
||||
fun updateBg() {
|
||||
_binding ?: return
|
||||
val units = profileFunction.getUnits()
|
||||
binding.infoLayout.bg.text = overviewData.lastBg?.valueToUnitsString(units)
|
||||
?: rh.gs(R.string.notavailable)
|
||||
binding.infoLayout.bg.setTextColor(overviewData.lastBgColor)
|
||||
binding.infoLayout.bg.setTextColor(overviewData.lastBgColor(context))
|
||||
binding.infoLayout.arrow.setImageResource(trendCalculator.getTrendArrow(overviewData.lastBg).directionToIcon())
|
||||
binding.infoLayout.arrow.setColorFilter(overviewData.lastBgColor)
|
||||
binding.infoLayout.arrow.setColorFilter(overviewData.lastBgColor(context))
|
||||
binding.infoLayout.arrow.contentDescription = overviewData.lastBgDescription + " " + rh.gs(R.string.and) + " " + trendCalculator.getTrendDescription(overviewData.lastBg)
|
||||
|
||||
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
|
||||
if (glucoseStatus != null) {
|
||||
binding.infoLayout.deltaLarge.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.deltaLarge.setTextColor(overviewData.lastBgColor)
|
||||
binding.infoLayout.deltaLarge.setTextColor(overviewData.lastBgColor(context))
|
||||
binding.infoLayout.delta.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)
|
||||
|
@ -809,70 +802,76 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateProfile(from: String) {
|
||||
fun updateProfile() {
|
||||
_binding ?: return
|
||||
val profileBackgroundColor =
|
||||
profileFunction.getProfile()?.let {
|
||||
if (it is ProfileSealed.EPS) {
|
||||
if (it.value.originalPercentage != 100 || it.value.originalTimeshift != 0L || it.value.originalDuration != 0L)
|
||||
rh.gc(R.color.ribbonWarning)
|
||||
else rh.gc(R.color.ribbonDefault)
|
||||
rh.gac(context, R.attr.ribbonWarningColor)
|
||||
else rh.gac(context, R.attr.ribbonDefaultColor)
|
||||
} else if (it is ProfileSealed.PS) {
|
||||
rh.gc(R.color.ribbonDefault)
|
||||
rh.gac(context, R.attr.ribbonDefaultColor)
|
||||
} else {
|
||||
rh.gc(R.color.ribbonDefault)
|
||||
rh.gac(context, R.attr.ribbonDefaultColor)
|
||||
}
|
||||
} ?: rh.gc(R.color.ribbonCritical)
|
||||
} ?: rh.gac(context, R.attr.ribbonCriticalColor)
|
||||
|
||||
val profileTextColor =
|
||||
profileFunction.getProfile()?.let {
|
||||
if (it is ProfileSealed.EPS) {
|
||||
if (it.value.originalPercentage != 100 || it.value.originalTimeshift != 0L || it.value.originalDuration != 0L)
|
||||
rh.gc(R.color.ribbonTextWarning)
|
||||
else rh.gc(R.color.ribbonTextDefault)
|
||||
rh.gac(context, R.attr.ribbonTextWarningColor)
|
||||
else rh.gac(context, R.attr.ribbonTextDefaultColor)
|
||||
} else if (it is ProfileSealed.PS) {
|
||||
rh.gc(R.color.ribbonTextDefault)
|
||||
rh.gac(context, R.attr.ribbonTextDefaultColor)
|
||||
} else {
|
||||
rh.gc(R.color.ribbonTextDefault)
|
||||
rh.gac(context, R.attr.ribbonTextDefaultColor)
|
||||
}
|
||||
} ?: rh.gc(R.color.ribbonTextDefault)
|
||||
} ?: rh.gac(context, R.attr.ribbonTextDefaultColor)
|
||||
|
||||
binding.activeProfile.text = profileFunction.getProfileNameWithRemainingTime()
|
||||
binding.activeProfile.setBackgroundColor(profileBackgroundColor)
|
||||
binding.activeProfile.setTextColor(profileTextColor)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateTemporaryBasal(from: String) {
|
||||
binding.infoLayout.baseBasal.text = overviewData.temporaryBasalText
|
||||
binding.infoLayout.baseBasal.setTextColor(overviewData.temporaryBasalColor)
|
||||
binding.infoLayout.baseBasalIcon.setImageResource(overviewData.temporaryBasalIcon)
|
||||
private fun updateTemporaryBasal() {
|
||||
_binding ?: return
|
||||
binding.infoLayout.baseBasal.text = overviewData.temporaryBasalText(iobCobCalculator)
|
||||
binding.infoLayout.baseBasal.setTextColor(overviewData.temporaryBasalColor(context, iobCobCalculator))
|
||||
binding.infoLayout.baseBasalIcon.setImageResource(overviewData.temporaryBasalIcon(iobCobCalculator))
|
||||
binding.infoLayout.basalLayout.setOnClickListener {
|
||||
activity?.let { OKDialog.show(it, rh.gs(R.string.basal), overviewData.temporaryBasalDialogText) }
|
||||
activity?.let { OKDialog.show(it, rh.gs(R.string.basal), overviewData.temporaryBasalDialogText(iobCobCalculator)) }
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateExtendedBolus(from: String) {
|
||||
private fun updateExtendedBolus() {
|
||||
_binding ?: return
|
||||
val pump = activePlugin.activePump
|
||||
binding.infoLayout.extendedBolus.text = overviewData.extendedBolusText
|
||||
binding.infoLayout.extendedBolus.text = overviewData.extendedBolusText(iobCobCalculator)
|
||||
binding.infoLayout.extendedLayout.setOnClickListener {
|
||||
activity?.let { OKDialog.show(it, rh.gs(R.string.extended_bolus), overviewData.extendedBolusDialogText) }
|
||||
activity?.let { OKDialog.show(it, rh.gs(R.string.extended_bolus), overviewData.extendedBolusDialogText(iobCobCalculator)) }
|
||||
}
|
||||
binding.infoLayout.extendedLayout.visibility = (iobCobCalculator.getExtendedBolus(dateUtil.now()) != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateTime(from: String) {
|
||||
fun updateTime() {
|
||||
_binding ?: return
|
||||
binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now())
|
||||
// Status lights
|
||||
val isPatchPump = activePlugin.activePump.pumpDescription.isPatchPump
|
||||
val pump = activePlugin.activePump
|
||||
val isPatchPump = pump.pumpDescription.isPatchPump
|
||||
binding.statusLightsLayout.apply {
|
||||
cannulaOrPatch.setImageResource(if (isPatchPump) R.drawable.ic_patch_pump_outline else R.drawable.ic_cp_age_cannula)
|
||||
cannulaOrPatch.contentDescription = rh.gs(if (isPatchPump) R.string.statuslights_patch_pump_age else R.string.statuslights_cannula_age)
|
||||
cannulaOrPatch.scaleX = if (isPatchPump) 1.4f else 2f
|
||||
cannulaOrPatch.scaleY = cannulaOrPatch.scaleX
|
||||
insulinAge.visibility = isPatchPump.not().toVisibility()
|
||||
batteryLayout.visibility = (!isPatchPump || pump.pumpDescription.useHardwareLink).toVisibility()
|
||||
pbAge.visibility = (pump.pumpDescription.isBatteryReplaceable || pump.isBatteryChangeLoggingEnabled()).toVisibility()
|
||||
val useBatteryLevel = (pump.model() == PumpType.OMNIPOD_EROS && pump is OmnipodErosPumpPlugin)
|
||||
|| (pump.model() != PumpType.ACCU_CHEK_COMBO && pump.model() != PumpType.OMNIPOD_DASH)
|
||||
batteryLevel.visibility = useBatteryLevel.toVisibility()
|
||||
statusLights.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
|
||||
}
|
||||
statusLightHandler.updateStatusLights(
|
||||
|
@ -888,14 +887,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
processAps()
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateIobCob(from: String) {
|
||||
binding.infoLayout.iob.text = overviewData.iobText
|
||||
fun updateIobCob() {
|
||||
_binding ?: return
|
||||
binding.infoLayout.iob.text = overviewData.iobText(iobCobCalculator)
|
||||
binding.infoLayout.iobLayout.setOnClickListener {
|
||||
activity?.let { OKDialog.show(it, rh.gs(R.string.iob), overviewData.iobDialogText) }
|
||||
activity?.let { OKDialog.show(it, rh.gs(R.string.iob), overviewData.iobDialogText(iobCobCalculator)) }
|
||||
}
|
||||
// cob
|
||||
var cobText = overviewData.cobInfo?.displayText(rh, dateUtil, buildHelper.isEngineeringMode()) ?: rh.gs(R.string.value_unavailable_short)
|
||||
var cobText = overviewData.cobInfo(iobCobCalculator).displayText(rh, dateUtil, buildHelper.isEngineeringMode()) ?: rh.gs(R.string.value_unavailable_short)
|
||||
|
||||
val constraintsProcessed = loop.lastRun?.constraintsProcessed
|
||||
val lastRun = loop.lastRun
|
||||
|
@ -916,14 +915,13 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateTemporaryTarget(from: String) {
|
||||
fun updateTemporaryTarget() {
|
||||
_binding ?: return
|
||||
val units = profileFunction.getUnits()
|
||||
if (overviewData.temporaryTarget?.isInProgress(dateUtil) == false) overviewData.temporaryTarget = null
|
||||
val tempTarget = overviewData.temporaryTarget
|
||||
if (tempTarget != null) {
|
||||
binding.tempTarget.setTextColor(rh.gc(R.color.ribbonTextWarning))
|
||||
binding.tempTarget.setBackgroundColor(rh.gc(R.color.ribbonWarning))
|
||||
binding.tempTarget.setTextColor(rh.gac(context, R.attr.ribbonTextWarningColor))
|
||||
binding.tempTarget.setBackgroundColor(rh.gac(context, R.attr.ribbonWarningColor))
|
||||
binding.tempTarget.text = Profile.toTargetRangeString(tempTarget.lowTarget, tempTarget.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.end, rh)
|
||||
} else {
|
||||
// If the target is not the same as set in the profile then oref has overridden it
|
||||
|
@ -933,19 +931,19 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
if (targetUsed != 0.0 && abs(profile.getTargetMgdl() - targetUsed) > 0.01) {
|
||||
aapsLogger.debug("Adjusted target. Profile: ${profile.getTargetMgdl()} APS: $targetUsed")
|
||||
binding.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, GlucoseUnit.MGDL, units)
|
||||
binding.tempTarget.setTextColor(rh.gc(R.color.ribbonTextWarning))
|
||||
binding.tempTarget.setBackgroundColor(rh.gc(R.color.tempTargetBackground))
|
||||
binding.tempTarget.setTextColor(rh.gac(context, R.attr.ribbonTextWarningColor))
|
||||
binding.tempTarget.setBackgroundColor(rh.gac(context, R.attr.tempTargetBackgroundColor))
|
||||
} else {
|
||||
binding.tempTarget.setTextColor(rh.gc(R.color.ribbonTextDefault))
|
||||
binding.tempTarget.setBackgroundColor(rh.gc(R.color.ribbonDefault))
|
||||
binding.tempTarget.setTextColor(rh.gac(context, R.attr.ribbonTextDefaultColor))
|
||||
binding.tempTarget.setBackgroundColor(rh.gac(context, R.attr.ribbonDefaultColor))
|
||||
binding.tempTarget.text = Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateGraph(from: String) {
|
||||
private fun updateGraph() {
|
||||
_binding ?: return
|
||||
val pump = activePlugin.activePump
|
||||
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData)
|
||||
val menuChartSettings = overviewMenus.setting
|
||||
|
@ -953,6 +951,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal])
|
||||
if (buildHelper.isDev()) graphData.addBucketedData()
|
||||
graphData.addTreatments()
|
||||
if (menuChartSettings[0][OverviewMenus.CharType.TREAT.ordinal])
|
||||
graphData.addTherapyEvents()
|
||||
if (menuChartSettings[0][OverviewMenus.CharType.ACT.ordinal])
|
||||
graphData.addActivity(0.8)
|
||||
if ((pump.pumpDescription.isTempBasalCapable || config.NSCLIENT) && menuChartSettings[0][OverviewMenus.CharType.BAS.ordinal])
|
||||
|
@ -1023,13 +1023,14 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateCalcProgress(from: String) {
|
||||
binding.graphsLayout.iobCalculationProgress.text = overviewData.calcProgress
|
||||
private fun updateCalcProgress() {
|
||||
_binding ?: return
|
||||
binding.progressBar.progress = overviewData.calcProgressPct
|
||||
binding.progressBar.visibility = (overviewData.calcProgressPct != 100).toVisibility()
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateSensitivity(from: String) {
|
||||
private fun updateSensitivity() {
|
||||
_binding ?: return
|
||||
if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) {
|
||||
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_swap_vert_black_48dp_green)
|
||||
} else {
|
||||
|
@ -1037,20 +1038,20 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
}
|
||||
|
||||
binding.infoLayout.sensitivity.text =
|
||||
overviewData.lastAutosensData?.let { autosensData ->
|
||||
overviewData.lastAutosensData(iobCobCalculator)?.let { autosensData ->
|
||||
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
|
||||
} ?: ""
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updatePumpStatus(from: String) {
|
||||
private fun updatePumpStatus() {
|
||||
_binding ?: return
|
||||
val status = overviewData.pumpStatus
|
||||
binding.pumpStatus.text = status
|
||||
binding.pumpStatusLayout.visibility = (status != "").toVisibility()
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun updateNotification(from: String) {
|
||||
private fun updateNotification() {
|
||||
_binding ?: return
|
||||
binding.notifications.let { notificationStore.updateNotifications(it) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview
|
||||
|
||||
import android.content.Context
|
||||
import android.text.SpannableString
|
||||
import android.text.style.BackgroundColorSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.widget.ImageButton
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
|
@ -31,18 +34,18 @@ class OverviewMenus @Inject constructor(
|
|||
private val loop: Loop,
|
||||
private val config: Config
|
||||
) {
|
||||
|
||||
enum class CharType(@StringRes val nameId: Int, @ColorRes val colorId: Int, val primary: Boolean, val secondary: Boolean, @StringRes val shortnameId: Int) {
|
||||
PRE(R.string.overview_show_predictions, R.color.prediction, primary = true, secondary = false, shortnameId = R.string.prediction_shortname),
|
||||
BAS(R.string.overview_show_basals, R.color.basal, primary = true, secondary = false, shortnameId = R.string.basal_shortname),
|
||||
ABS(R.string.overview_show_absinsulin, R.color.iob, primary = false, secondary = true, shortnameId = R.string.abs_insulin_shortname),
|
||||
IOB(R.string.overview_show_iob, R.color.iob, primary = false, secondary = true, shortnameId = R.string.iob),
|
||||
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true, shortnameId = R.string.cob),
|
||||
DEV(R.string.overview_show_deviations, R.color.bgi, primary = false, secondary = true, shortnameId = R.string.deviation_shortname),
|
||||
BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true, shortnameId = R.string.bgi_shortname),
|
||||
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true, shortnameId = R.string.sensitivity_shortname),
|
||||
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = false, shortnameId = R.string.activity_shortname),
|
||||
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true, shortnameId = R.string.devslope_shortname)
|
||||
enum class CharType(@StringRes val nameId: Int, @AttrRes val attrId: Int, @AttrRes val attrTextId: Int, val primary: Boolean, val secondary: Boolean, @StringRes val shortnameId: Int) {
|
||||
PRE(R.string.overview_show_predictions, R.attr.predictionColor, R.attr.menuTextColor, primary = true, secondary = false, shortnameId = R.string.prediction_shortname),
|
||||
TREAT(R.string.overview_show_treatments, R.attr.predictionColor, R.attr.menuTextColor, primary = true, secondary = false, shortnameId = R.string.treatments_shortname),
|
||||
BAS(R.string.overview_show_basals, R.attr.basal, R.attr.menuTextColor, primary = true, secondary = false,shortnameId = R.string.basal_shortname),
|
||||
ABS(R.string.overview_show_absinsulin, R.attr.iobColor, R.attr.menuTextColor, primary = false, secondary = true,shortnameId = R.string.abs_insulin_shortname),
|
||||
IOB(R.string.overview_show_iob, R.attr.iobColor, R.attr.menuTextColor, primary = false, secondary = true,shortnameId = R.string.iob),
|
||||
COB(R.string.overview_show_cob, R.attr.cobColor, R.attr.menuTextColor, primary = false, secondary = true,shortnameId = R.string.cob),
|
||||
DEV(R.string.overview_show_deviations, R.attr.bgiColor, R.attr.menuTextColor, primary = false, secondary = true,shortnameId = R.string.deviation_shortname),
|
||||
BGI(R.string.overview_show_bgi, R.attr.bgiColor, R.attr.menuTextColor, primary = false, secondary = true,shortnameId = R.string.bgi_shortname),
|
||||
SEN(R.string.overview_show_sensitivity, R.attr.ratioColor, R.attr.menuTextColorInverse, primary = false, secondary = true,shortnameId = R.string.sensitivity_shortname),
|
||||
ACT(R.string.overview_show_activity, R.attr.activityColor, R.attr.menuTextColor, primary = true, secondary = false,shortnameId = R.string.activity_shortname),
|
||||
DEVSLOPE(R.string.overview_show_deviationslope, R.attr.devslopeposColor, R.attr.menuTextColor, primary = false, secondary = true,shortnameId = R.string.devslope_shortname)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -86,7 +89,7 @@ class OverviewMenus @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun setupChartMenu(chartButton: ImageButton) {
|
||||
fun setupChartMenu(context: Context, chartButton: ImageButton) {
|
||||
val settingsCopy = setting
|
||||
val numOfGraphs = settingsCopy.size // 1 main + x secondary
|
||||
|
||||
|
@ -119,8 +122,9 @@ class OverviewMenus @Inject constructor(
|
|||
if (insert) {
|
||||
val item = popup.menu.add(Menu.NONE, m.ordinal + 100 * (g + 1), Menu.NONE, rh.gs(m.nameId))
|
||||
val title = item.title
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(rh.gc(m.colorId)), 0, s.length, 0)
|
||||
val s = SpannableString(" " + title + " ")
|
||||
s.setSpan(ForegroundColorSpan(rh.gac(context, m.attrTextId)), 0, s.length, 0)
|
||||
s.setSpan(BackgroundColorSpan(rh.gac(context, m.attrId)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = settingsCopy[g][m.ordinal]
|
||||
|
@ -152,7 +156,7 @@ class OverviewMenus @Inject constructor(
|
|||
}
|
||||
}
|
||||
storeGraphConfig()
|
||||
setupChartMenu(chartButton)
|
||||
setupChartMenu(context, chartButton)
|
||||
rxBus.send(EventRefreshOverview("OnMenuItemClickListener", now = true))
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
|
|
|
@ -4,25 +4,26 @@ import androidx.preference.PreferenceFragmentCompat
|
|||
import androidx.preference.SwitchPreference
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||
import info.nightscout.androidaps.extensions.*
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventLoopInvoked
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.Overview
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.*
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewCalcProgress
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucketedDataCreated
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -41,9 +42,6 @@ class OverviewPlugin @Inject constructor(
|
|||
private val aapsSchedulers: AapsSchedulers,
|
||||
rh: ResourceHelper,
|
||||
private val config: Config,
|
||||
private val dateUtil: DateUtil,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val repository: AppRepository,
|
||||
private val overviewData: OverviewData,
|
||||
private val overviewMenus: OverviewMenus
|
||||
) : PluginBase(
|
||||
|
@ -89,62 +87,9 @@ class OverviewPlugin @Inject constructor(
|
|||
disposable += rxBus
|
||||
.toObservable(EventIobCalculationProgress::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ overviewData.calcProgress = it.progress; overviewBus.send(EventUpdateOverviewCalcProgress("EventIobCalculationProgress")) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ overviewBus.send(EventUpdateOverviewTemporaryBasal("EventTempBasalChange")) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ overviewBus.send(EventUpdateOverviewExtendedBolus("EventExtendedBolusChange")) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventNewBG::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadBg("EventNewBG") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempTargetChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ loadTemporaryTarget("EventTempTargetChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
loadIobCobResults("EventTreatmentChange")
|
||||
overviewData.prepareTreatmentsData("EventTreatmentChange")
|
||||
overviewBus.send(EventUpdateOverviewGraph("EventTreatmentChange"))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTherapyEventChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
overviewData.prepareTreatmentsData("EventTherapyEventChange")
|
||||
overviewBus.send(EventUpdateOverviewGraph("EventTherapyEventChange"))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventBucketedDataCreated::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
overviewData.prepareBucketedData("EventBucketedDataCreated")
|
||||
overviewData.prepareBgData("EventBucketedDataCreated")
|
||||
overviewBus.send(EventUpdateOverviewGraph("EventBucketedDataCreated"))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventLoopInvoked::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ overviewData.preparePredictions("EventLoopInvoked") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
loadProfile("EventEffectiveProfileSwitchChanged")
|
||||
overviewData.prepareBasalData("EventEffectiveProfileSwitchChanged")
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
if (it.cause !is EventCustomCalculationFinished) refreshLoop("EventAutosensCalculationFinished")
|
||||
overviewData.calcProgressPct = it.pass.finalPercent(it.progressPct)
|
||||
overviewBus.send(EventUpdateOverviewCalcProgress("EventIobCalculationProgress"))
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventPumpStatusChanged::class.java)
|
||||
|
@ -152,20 +97,7 @@ class OverviewPlugin @Inject constructor(
|
|||
.subscribe({
|
||||
overviewData.pumpStatus = it.getStatus(rh)
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event ->
|
||||
if (event.isChanged(rh, R.string.key_units)) {
|
||||
overviewData.reset()
|
||||
overviewData.prepareBucketedData("EventBucketedDataCreated")
|
||||
overviewData.prepareBgData("EventBucketedDataCreated")
|
||||
overviewBus.send(EventUpdateOverviewGraph("EventBucketedDataCreated"))
|
||||
loadAll("EventPreferenceChange")
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
|
||||
Thread { loadAll("onResume") }.start()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
|
@ -243,7 +175,7 @@ class OverviewPlugin @Inject constructor(
|
|||
.storeDouble(R.string.key_statuslights_bat_critical, sp, rh)
|
||||
.storeInt(R.string.key_boluswizard_percentage, sp, rh)
|
||||
}
|
||||
|
||||
/*
|
||||
@Volatile
|
||||
var runningRefresh = false
|
||||
override fun refreshLoop(from: String) {
|
||||
|
@ -284,38 +216,5 @@ class OverviewPlugin @Inject constructor(
|
|||
overviewBus.send(EventUpdateOverviewGraph(from))
|
||||
aapsLogger.debug(LTag.UI, "loadAll finished")
|
||||
}
|
||||
|
||||
private fun loadProfile(from: String) {
|
||||
overviewBus.send(EventUpdateOverviewProfile(from))
|
||||
}
|
||||
|
||||
private fun loadTemporaryTarget(from: String) {
|
||||
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
if (tempTarget is ValueWrapper.Existing) overviewData.temporaryTarget = tempTarget.value
|
||||
else overviewData.temporaryTarget = null
|
||||
overviewBus.send(EventUpdateOverviewTemporaryTarget(from))
|
||||
}
|
||||
|
||||
private fun loadAsData(from: String) {
|
||||
overviewData.lastAutosensData = iobCobCalculator.ads.getLastAutosensData("Overview", aapsLogger, dateUtil)
|
||||
overviewBus.send(EventUpdateOverviewSensitivity(from))
|
||||
}
|
||||
|
||||
private fun loadBg(from: String) {
|
||||
val gvWrapped = repository.getLastGlucoseValueWrapped().blockingGet()
|
||||
if (gvWrapped is ValueWrapper.Existing) overviewData.lastBg = gvWrapped.value
|
||||
else overviewData.lastBg = null
|
||||
overviewBus.send(EventUpdateOverviewBg(from))
|
||||
}
|
||||
|
||||
private fun loadIobCobResults(from: String) {
|
||||
overviewData.bolusIob = iobCobCalculator.calculateIobFromBolus().round()
|
||||
overviewData.basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
|
||||
overviewData.cobInfo = iobCobCalculator.getCobInfo(true, "Overview COB")
|
||||
val lastCarbs = repository.getLastCarbsRecordWrapped().blockingGet()
|
||||
overviewData.lastCarbsTime = if (lastCarbs is ValueWrapper.Existing) lastCarbs.value.timestamp else 0L
|
||||
|
||||
overviewBus.send(EventUpdateOverviewIobCob(from))
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -42,7 +41,7 @@ class StatusLightHandler @Inject constructor(
|
|||
handleAge(careportal_cannula_age, TherapyEvent.Type.CANNULA_CHANGE, R.string.key_statuslights_cage_warning, 48.0, R.string.key_statuslights_cage_critical, 72.0)
|
||||
handleAge(careportal_insulin_age, TherapyEvent.Type.INSULIN_CHANGE, R.string.key_statuslights_iage_warning, 72.0, R.string.key_statuslights_iage_critical, 144.0)
|
||||
handleAge(careportal_sensor_age, TherapyEvent.Type.SENSOR_CHANGE, R.string.key_statuslights_sage_warning, 216.0, R.string.key_statuslights_sage_critical, 240.0)
|
||||
if (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)) {
|
||||
if (pump.pumpDescription.isBatteryReplaceable || pump.isBatteryChangeLoggingEnabled()) {
|
||||
handleAge(careportal_pb_age, TherapyEvent.Type.PUMP_BATTERY_CHANGE, R.string.key_statuslights_bage_warning, 216.0, R.string.key_statuslights_bage_critical, 240.0)
|
||||
}
|
||||
if (!config.NSCLIENT) {
|
||||
|
@ -58,16 +57,16 @@ class StatusLightHandler @Inject constructor(
|
|||
}
|
||||
|
||||
if (!config.NSCLIENT) {
|
||||
if (pump.model() == PumpType.OMNIPOD_DASH) {
|
||||
// Omnipod Dash does not report its battery level
|
||||
careportal_battery_level?.text = rh.gs(R.string.notavailable)
|
||||
careportal_battery_level?.setTextColor(Color.WHITE)
|
||||
} else if (pump.model() == PumpType.OMNIPOD_EROS && pump is OmnipodErosPumpPlugin) { // instance of check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below
|
||||
// The Omnipod Eros does not report its battery level. However, some RileyLink alternatives do.
|
||||
// Depending on the user's configuration, we will either show the battery level reported by the RileyLink or "n/a"
|
||||
handleOmnipodErosBatteryLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%", pump.isUseRileyLinkBatteryLevel)
|
||||
} else if (pump.model() != PumpType.ACCU_CHEK_COMBO) {
|
||||
// The Omnipod Eros does not report its battery level. However, some RileyLink alternatives do.
|
||||
// Depending on the user's configuration, we will either show the battery level reported by the RileyLink or "n/a"
|
||||
// Pump instance check is needed because at startup, the pump can still be VirtualPumpPlugin and that will cause a crash
|
||||
val erosBatteryLinkAvailable = pump.model() == PumpType.OMNIPOD_EROS && pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel
|
||||
|
||||
if (pump.model().supportBatteryLevel || erosBatteryLinkAvailable) {
|
||||
handleLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%")
|
||||
} else {
|
||||
careportal_battery_level?.text = rh.gs(R.string.notavailable)
|
||||
careportal_battery_level?.setTextColor(rh.gac(careportal_battery_level.context, R.attr.defaultTextColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,13 +103,4 @@ class StatusLightHandler @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun handleOmnipodErosBatteryLevel(view: TextView?, criticalSetting: Int, criticalDefaultValue: Double, warnSetting: Int, warnDefaultValue: Double, level: Double, units: String, useRileyLinkBatteryLevel: Boolean) {
|
||||
if (useRileyLinkBatteryLevel) {
|
||||
handleLevel(view, criticalSetting, criticalDefaultValue, warnSetting, warnDefaultValue, level, units)
|
||||
} else {
|
||||
view?.text = rh.gs(R.string.notavailable)
|
||||
view?.setTextColor(Color.WHITE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,32 +2,28 @@ package info.nightscout.androidaps.plugins.general.overview.activities
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import androidx.core.util.forEach
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_DRAG
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.DOWN
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.END
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.START
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.UP
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.DaggerAppCompatActivityWithResult
|
||||
import info.nightscout.androidaps.databinding.OverviewQuickwizardlistActivityBinding
|
||||
import info.nightscout.androidaps.databinding.OverviewQuickwizardlistItemBinding
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.utils.dragHelpers.ItemTouchHelperAdapter
|
||||
import info.nightscout.androidaps.utils.dragHelpers.OnStartDragListener
|
||||
import info.nightscout.androidaps.utils.dragHelpers.SimpleItemTouchHelperCallback
|
||||
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
|
||||
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||
|
@ -36,7 +32,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
|||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
||||
class QuickWizardListActivity : DaggerAppCompatActivityWithResult(), OnStartDragListener {
|
||||
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
|
@ -46,134 +42,78 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
@Inject lateinit var sp: SP
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
private lateinit var actionHelper: ActionModeHelper<QuickWizardEntry>
|
||||
private val itemTouchHelper = ItemTouchHelper(SimpleItemTouchHelperCallback())
|
||||
private lateinit var binding: OverviewQuickwizardlistActivityBinding
|
||||
|
||||
private val itemTouchHelper by lazy {
|
||||
val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback(UP or DOWN or START or END, 0) {
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val adapter = recyclerView.adapter as RecyclerViewAdapter
|
||||
val from = viewHolder.layoutPosition
|
||||
val to = target.layoutPosition
|
||||
adapter.moveItem(from, to)
|
||||
adapter.notifyItemMoved(from, to)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
}
|
||||
|
||||
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||
super.onSelectedChanged(viewHolder, actionState)
|
||||
|
||||
if (actionState == ACTION_STATE_DRAG) {
|
||||
viewHolder?.itemView?.alpha = 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||
super.clearView(recyclerView, viewHolder)
|
||||
|
||||
viewHolder.itemView.alpha = 1.0f
|
||||
|
||||
val adapter = recyclerView.adapter as RecyclerViewAdapter
|
||||
adapter.onDrop()
|
||||
}
|
||||
}
|
||||
|
||||
ItemTouchHelper(simpleItemTouchCallback)
|
||||
}
|
||||
|
||||
fun startDragging(viewHolder: RecyclerView.ViewHolder) {
|
||||
override fun onStartDrag(viewHolder: RecyclerView.ViewHolder) {
|
||||
itemTouchHelper.startDrag(viewHolder)
|
||||
}
|
||||
|
||||
private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>() {
|
||||
private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>(), ItemTouchHelperAdapter {
|
||||
|
||||
private inner class QuickWizardEntryViewHolder(val binding: OverviewQuickwizardlistItemBinding, val fragmentManager: FragmentManager) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickWizardEntryViewHolder {
|
||||
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false)
|
||||
val viewHolder = QuickWizardEntryViewHolder(itemView, fragmentManager)
|
||||
|
||||
viewHolder.handleView.setOnTouchListener { _, event ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
startDragging(viewHolder)
|
||||
}
|
||||
return@setOnTouchListener true
|
||||
}
|
||||
|
||||
return viewHolder
|
||||
val binding = OverviewQuickwizardlistItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return QuickWizardEntryViewHolder(binding, fragmentManager)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: QuickWizardEntryViewHolder, position: Int) {
|
||||
holder.from.text = dateUtil.timeString(quickWizard[position].validFromDate())
|
||||
holder.to.text = dateUtil.timeString(quickWizard[position].validToDate())
|
||||
val wearControl = sp.getBoolean(R.string.key_wear_control, false)
|
||||
|
||||
if (wearControl) {
|
||||
holder.handleView.visibility = View.VISIBLE
|
||||
val entry = quickWizard[position]
|
||||
holder.binding.from.text = dateUtil.timeString(entry.validFromDate())
|
||||
holder.binding.to.text = dateUtil.timeString(entry.validToDate())
|
||||
holder.binding.buttonText.text = entry.buttonText()
|
||||
holder.binding.carbs.text = rh.gs(R.string.format_carbs, entry.carbs())
|
||||
if (entry.device() == QuickWizardEntry.DEVICE_ALL) {
|
||||
holder.binding.device.visibility = View.GONE
|
||||
} else {
|
||||
holder.handleView.visibility = View.GONE
|
||||
}
|
||||
if (quickWizard[position].device() == QuickWizardEntry.DEVICE_ALL) {
|
||||
holder.device.visibility = View.GONE
|
||||
} else {
|
||||
holder.device.visibility = View.VISIBLE
|
||||
holder.device.setImageResource(
|
||||
holder.binding.device.visibility = View.VISIBLE
|
||||
holder.binding.device.setImageResource(
|
||||
when (quickWizard[position].device()) {
|
||||
QuickWizardEntry.DEVICE_WATCH -> R.drawable.ic_watch
|
||||
else -> R.drawable.ic_smartphone
|
||||
}
|
||||
)
|
||||
}
|
||||
holder.buttonText.text = quickWizard[position].buttonText()
|
||||
holder.carbs.text = rh.gs(R.string.format_carbs, quickWizard[position].carbs())
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = quickWizard.size()
|
||||
|
||||
private inner class QuickWizardEntryViewHolder(itemView: View, var fragmentManager: FragmentManager) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
val buttonText: TextView = itemView.findViewById(R.id.overview_quickwizard_item_buttonText)
|
||||
val carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs)
|
||||
val from: TextView = itemView.findViewById(R.id.overview_quickwizard_item_from)
|
||||
val handleView: ImageView = itemView.findViewById(R.id.handleView)
|
||||
val device: ImageView = itemView.findViewById(R.id.overview_quickwizard_item_device)
|
||||
val to: TextView = itemView.findViewById(R.id.overview_quickwizard_item_to)
|
||||
private val editButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_edit_button)
|
||||
private val removeButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_remove_button)
|
||||
|
||||
init {
|
||||
editButton.setOnClickListener {
|
||||
holder.binding.root.setOnClickListener {
|
||||
if (actionHelper.isNoAction) {
|
||||
val manager = fragmentManager
|
||||
val editQuickWizardDialog = EditQuickWizardDialog()
|
||||
val bundle = Bundle()
|
||||
bundle.putInt("position", bindingAdapterPosition)
|
||||
bundle.putInt("position", position)
|
||||
editQuickWizardDialog.arguments = bundle
|
||||
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
||||
}
|
||||
removeButton.setOnClickListener {
|
||||
quickWizard.remove(bindingAdapterPosition)
|
||||
rxBus.send(EventQuickWizardChange())
|
||||
} else if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, entry, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
}
|
||||
holder.binding.sortHandle.setOnTouchListener { _, event ->
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
onStartDrag(holder)
|
||||
return@setOnTouchListener true
|
||||
}
|
||||
return@setOnTouchListener false
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, entry, value)
|
||||
}
|
||||
holder.binding.sortHandle.visibility = actionHelper.isSorting.toVisibility()
|
||||
holder.binding.cbRemove.visibility = actionHelper.isRemoving.toVisibility()
|
||||
}
|
||||
|
||||
fun moveItem(from: Int, to: Int) {
|
||||
Log.i("QuickWizard", "moveItem")
|
||||
quickWizard.move(from, to)
|
||||
override fun getItemCount() = quickWizard.size()
|
||||
|
||||
override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
|
||||
binding.recyclerview.adapter?.notifyItemMoved(fromPosition, toPosition)
|
||||
quickWizard.move(fromPosition, toPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
fun onDrop() {
|
||||
Log.i("QuickWizard", "onDrop")
|
||||
rxBus.send(EventQuickWizardChange())
|
||||
}
|
||||
override fun onDrop() = rxBus.send(EventQuickWizardChange())
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -181,6 +121,11 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
binding = OverviewQuickwizardlistActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
actionHelper = ActionModeHelper(rh, this)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
actionHelper.enableSort = true
|
||||
|
||||
title = rh.gs(R.string.quickwizard)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
|
@ -191,6 +136,7 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
itemTouchHelper.attachToRecyclerView(binding.recyclerview)
|
||||
|
||||
binding.addButton.setOnClickListener {
|
||||
actionHelper.finish()
|
||||
val manager = supportFragmentManager
|
||||
val editQuickWizardDialog = EditQuickWizardDialog()
|
||||
editQuickWizardDialog.show(manager, "EditQuickWizardDialog")
|
||||
|
@ -210,9 +156,25 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
|
||||
override fun onPause() {
|
||||
disposable.clear()
|
||||
actionHelper.finish()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
private fun removeSelected(selectedItems: SparseArray<QuickWizardEntry>) {
|
||||
OKDialog.showConfirmation(this, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, item ->
|
||||
quickWizard.remove(item.position)
|
||||
rxBus.send(EventQuickWizardChange())
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_actions, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
|
@ -220,6 +182,17 @@ class QuickWizardListActivity : DaggerAppCompatActivityWithResult() {
|
|||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
else -> actionHelper.onOptionsItemSelected(item)
|
||||
|
||||
}
|
||||
|
||||
private fun getConfirmationText(selectedItems: SparseArray<QuickWizardEntry>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val entry = selectedItems.valueAt(0)
|
||||
return "${rh.gs(R.string.remove_button)} ${entry.buttonText()} ${rh.gs(R.string.format_carbs, entry.carbs())}\n" +
|
||||
"${dateUtil.timeString(entry.validFromDate())} - ${dateUtil.timeString(entry.validToDate())}"
|
||||
}
|
||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
binding.from.setOnClickListener {
|
||||
context?.let {
|
||||
TimePickerDialog(
|
||||
it, R.style.MaterialPickerTheme,
|
||||
it,
|
||||
fromTimeSetListener,
|
||||
T.secs(fromSeconds.toLong()).hours().toInt(),
|
||||
T.secs((fromSeconds % 3600).toLong()).mins().toInt(),
|
||||
|
@ -124,7 +124,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
binding.to.setOnClickListener {
|
||||
context?.let {
|
||||
TimePickerDialog(
|
||||
it, R.style.MaterialPickerTheme,
|
||||
it,
|
||||
toTimeSetListener,
|
||||
T.secs(toSeconds.toLong()).hours().toInt(),
|
||||
T.secs((toSeconds % 3600).toLong()).mins().toInt(),
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventUpdateOverviewBg(val from: String) : Event()
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventUpdateOverviewExtendedBolus(val from: String) : Event()
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventUpdateOverviewProfile(val from: String) : Event()
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventUpdateOverviewTemporaryBasal(val from: String) : Event()
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventUpdateOverviewTemporaryTarget(val from: String) : Event()
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventUpdateOverviewTime(val from: String) : Event()
|
|
@ -66,7 +66,7 @@ class GraphData(
|
|||
addSeries(AreaGraphSeries(inRangeAreaDataPoints).also {
|
||||
it.color = 0
|
||||
it.isDrawBackground = true
|
||||
it.backgroundColor = rh.gc(R.color.inrangebackground)
|
||||
it.backgroundColor = rh.gac(graph.context,R.attr.inrangeBackground)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,11 @@ class GraphData(
|
|||
addSeries(overviewData.treatmentsSeries)
|
||||
}
|
||||
|
||||
fun addTherapyEvents() {
|
||||
maxY = maxOf(maxY, overviewData.maxTherapyEventValue)
|
||||
addSeries(overviewData.therapyEventSeries)
|
||||
}
|
||||
|
||||
fun addActivity(scale: Double) {
|
||||
addSeries(overviewData.activitySeries)
|
||||
addSeries(overviewData.activityPredictionSeries)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
|
@ -28,13 +29,11 @@ class BolusDataPoint @Inject constructor(
|
|||
override val shape
|
||||
get() = if (data.type == Bolus.Type.SMB) PointsWithLabelGraphSeries.Shape.SMB else PointsWithLabelGraphSeries.Shape.BOLUS
|
||||
|
||||
override val color
|
||||
get() =
|
||||
when {
|
||||
data.type == Bolus.Type.SMB -> rh.gc(R.color.tempbasal)
|
||||
data.isValid -> Color.CYAN
|
||||
else -> rh.gc(android.R.color.holo_red_light)
|
||||
}
|
||||
override fun color(context: Context?): Int =
|
||||
if (data.type == Bolus.Type.SMB) rh.gac(context, R.attr.smbColor)
|
||||
else if (data.isValid) rh.gac(context, R.attr.bolusDataPointColor)
|
||||
else rh.gac(context, R.attr.alarmColor)
|
||||
|
||||
|
||||
override fun setY(y: Double) {
|
||||
yValue = y
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||
|
||||
import android.content.Context
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.database.entities.Carbs
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
@ -18,7 +19,10 @@ class CarbsDataPoint @Inject constructor(
|
|||
override val duration = 0L
|
||||
override val size = 2f
|
||||
override val shape = PointsWithLabelGraphSeries.Shape.CARBS
|
||||
override val color get() = if (data.isValid) rh.gc(R.color.carbs) else rh.gc(android.R.color.holo_red_light)
|
||||
|
||||
override fun color(context: Context?): Int {
|
||||
return if (data.isValid) rh.gac(context, R.attr.cobColor) else rh.gac(context, R.attr.alarmColor)
|
||||
}
|
||||
|
||||
override fun setY(y: Double) {
|
||||
yValue = y
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
class EffectiveProfileSwitchDataPoint @Inject constructor(
|
||||
val data: EffectiveProfileSwitch
|
||||
val data: EffectiveProfileSwitch,
|
||||
private val rh: ResourceHelper
|
||||
) : DataPointWithLabelInterface {
|
||||
|
||||
private var yValue = 0.0
|
||||
|
@ -21,5 +25,7 @@ class EffectiveProfileSwitchDataPoint @Inject constructor(
|
|||
override val duration = 0L
|
||||
override val shape = PointsWithLabelGraphSeries.Shape.PROFILE
|
||||
override val size = 10f
|
||||
override val color = Color.CYAN
|
||||
override fun color(context: Context?): Int {
|
||||
return rh.gac(context, R.attr.profileSwitchColor)
|
||||
}
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.database.entities.ExtendedBolus
|
||||
import info.nightscout.androidaps.extensions.toStringTotal
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
class ExtendedBolusDataPoint @Inject constructor(
|
||||
val data: ExtendedBolus
|
||||
val data: ExtendedBolus,
|
||||
private val rh: ResourceHelper
|
||||
) : DataPointWithLabelInterface {
|
||||
|
||||
private var yValue = 0.0
|
||||
|
@ -17,7 +21,9 @@ class ExtendedBolusDataPoint @Inject constructor(
|
|||
override val duration get() = data.duration
|
||||
override val size = 10f
|
||||
override val shape = PointsWithLabelGraphSeries.Shape.EXTENDEDBOLUS
|
||||
override val color = Color.CYAN
|
||||
override fun color(context: Context?): Int {
|
||||
return rh.gac(context, R.attr.extBolusColor)
|
||||
}
|
||||
|
||||
override fun setY(y: Double) {
|
||||
yValue = y
|
||||
|
|
|
@ -261,7 +261,7 @@ public class FixedLineGraphSeries<E extends DataPointInterface> extends BaseSeri
|
|||
//fix: last value not drawn as datapoint. Draw first point here, and then on every step the end values (above)
|
||||
// float first_X = (float) x + (graphLeft + 1);
|
||||
// float first_Y = (float) (graphTop - y) + graphHeight;
|
||||
//TODO canvas.drawCircle(first_X, first_Y, dataPointsRadius, mPaint);
|
||||
// canvas.drawCircle(first_X, first_Y, dataPointsRadius, mPaint);
|
||||
}
|
||||
lastEndY = orgY;
|
||||
lastEndX = orgX;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||
|
||||
import android.content.Context
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
|
@ -27,30 +28,28 @@ class GlucoseValueDataPoint @Inject constructor(
|
|||
override val duration = 0L
|
||||
override val shape get() = if (isPrediction) PointsWithLabelGraphSeries.Shape.PREDICTION else PointsWithLabelGraphSeries.Shape.BG
|
||||
override val size = 1f
|
||||
override val color: Int
|
||||
get() {
|
||||
val units = profileFunction.getUnits()
|
||||
val lowLine = defaultValueHelper.determineLowLine()
|
||||
val highLine = defaultValueHelper.determineHighLine()
|
||||
return when {
|
||||
isPrediction -> predictionColor
|
||||
valueToUnits(units) < lowLine -> rh.gc(R.color.low)
|
||||
valueToUnits(units) > highLine -> rh.gc(R.color.high)
|
||||
else -> rh.gc(R.color.inrange)
|
||||
}
|
||||
override fun color(context: Context?): Int {
|
||||
val units = profileFunction.getUnits()
|
||||
val lowLine = defaultValueHelper.determineLowLine()
|
||||
val highLine = defaultValueHelper.determineHighLine()
|
||||
return when {
|
||||
isPrediction -> predictionColor(context)
|
||||
valueToUnits(units) < lowLine -> rh.gac(context, R.attr.bgLow)
|
||||
valueToUnits(units) > highLine -> rh.gac(context, R.attr.highColor)
|
||||
else -> rh.gac(context, R.attr.bgInRange)
|
||||
}
|
||||
}
|
||||
|
||||
val predictionColor: Int
|
||||
get() {
|
||||
private fun predictionColor (context: Context?): Int {
|
||||
return when (data.sourceSensor) {
|
||||
GlucoseValue.SourceSensor.IOB_PREDICTION -> rh.gc(R.color.iob)
|
||||
GlucoseValue.SourceSensor.COB_PREDICTION -> rh.gc(R.color.cob)
|
||||
GlucoseValue.SourceSensor.A_COB_PREDICTION -> -0x7f000001 and rh.gc(R.color.cob)
|
||||
GlucoseValue.SourceSensor.UAM_PREDICTION -> rh.gc(R.color.uam)
|
||||
GlucoseValue.SourceSensor.ZT_PREDICTION -> rh.gc(R.color.zt)
|
||||
else -> R.color.white
|
||||
GlucoseValue.SourceSensor.IOB_PREDICTION -> rh.gac(context, R.attr.iobColor)
|
||||
GlucoseValue.SourceSensor.COB_PREDICTION -> rh.gac(context, R.attr.cobColor)
|
||||
GlucoseValue.SourceSensor.A_COB_PREDICTION -> -0x7f000001 and rh.gac(context, R.attr.cobColor)
|
||||
GlucoseValue.SourceSensor.UAM_PREDICTION -> rh.gac(context, R.attr.uamColor)
|
||||
GlucoseValue.SourceSensor.ZT_PREDICTION -> rh.gac(context, R.attr.ztColor)
|
||||
else -> rh.gac( context,R.attr.defaultTextColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val isPrediction: Boolean
|
||||
get() = data.sourceSensor == GlucoseValue.SourceSensor.IOB_PREDICTION ||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||
|
||||
import android.content.Context
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.data.InMemoryGlucoseValue
|
||||
|
@ -24,5 +25,7 @@ class InMemoryGlucoseValueDataPoint @Inject constructor(
|
|||
override val duration = 0L
|
||||
override val shape = PointsWithLabelGraphSeries.Shape.BUCKETED_BG
|
||||
override val size = 0.3f
|
||||
override val color get() = rh.gc(R.color.white)
|
||||
override fun color(context: Context?): Int {
|
||||
return rh.gac(context, R.attr.inMemoryColor)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.overview.graphExtensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.core.R
|
||||
|
@ -59,14 +60,14 @@ class TherapyEventDataPoint @Inject constructor(
|
|||
}
|
||||
|
||||
override val size get() = if (rh.gb(R.bool.isTablet)) 12.0f else 10.0f
|
||||
override val color
|
||||
get() =
|
||||
when (data.type) {
|
||||
TherapyEvent.Type.ANNOUNCEMENT -> rh.gc(R.color.notificationAnnouncement)
|
||||
TherapyEvent.Type.NS_MBG -> Color.RED
|
||||
TherapyEvent.Type.FINGER_STICK_BG_VALUE -> Color.RED
|
||||
TherapyEvent.Type.EXERCISE -> Color.BLUE
|
||||
TherapyEvent.Type.APS_OFFLINE -> Color.GRAY and -0x7f000001
|
||||
else -> Color.GRAY
|
||||
}
|
||||
override fun color(context: Context?): Int {
|
||||
return when (data.type) {
|
||||
TherapyEvent.Type.ANNOUNCEMENT -> rh.gac(context, R.attr.notificationAnnouncement)
|
||||
TherapyEvent.Type.NS_MBG -> rh.gac(context, R.attr.therapyEvent_NS_MBG)
|
||||
TherapyEvent.Type.FINGER_STICK_BG_VALUE -> rh.gac(context, R.attr.therapyEvent_FINGER_STICK_BG_VALUE)
|
||||
TherapyEvent.Type.EXERCISE -> rh.gac(context, R.attr.therapyEvent_EXERCISE)
|
||||
TherapyEvent.Type.APS_OFFLINE -> rh.gac(context, R.attr.therapyEvent_APS_OFFLINE) and -0x7f000001
|
||||
else -> rh.gac(context, R.attr.therapyEvent_Default)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -164,11 +164,11 @@ class NotificationStore @Inject constructor(
|
|||
@Suppress("SetTextI18n")
|
||||
holder.binding.text.text = dateUtil.timeString(notification.date) + " " + notification.text
|
||||
when (notification.level) {
|
||||
Notification.URGENT -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationUrgent))
|
||||
Notification.NORMAL -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationNormal))
|
||||
Notification.LOW -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationLow))
|
||||
Notification.INFO -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationInfo))
|
||||
Notification.ANNOUNCEMENT -> holder.binding.cv.setBackgroundColor(rh.gc(R.color.notificationAnnouncement))
|
||||
Notification.URGENT -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationUrgent))
|
||||
Notification.NORMAL -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationNormal))
|
||||
Notification.LOW -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationLow))
|
||||
Notification.INFO -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationInfo))
|
||||
Notification.ANNOUNCEMENT -> holder.binding.cv.setBackgroundColor(rh.gac(R.attr.notificationAnnouncement))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,6 @@ class DummyService : DaggerService() {
|
|||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
// TODO: I guess this was moved here in order to adhere to the 5 seconds rule to call "startForeground" after a Service was called as Foreground service?
|
||||
// As onCreate() is not called every time a service is started, copied to onStartCommand().
|
||||
try {
|
||||
aapsLogger.debug("Starting DummyService with ID ${notificationHolder.notificationID} notification ${notificationHolder.notification}")
|
||||
startForeground(notificationHolder.notificationID, notificationHolder.notification)
|
||||
|
|
|
@ -9,17 +9,20 @@ import androidx.core.app.RemoteInput
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview
|
||||
import info.nightscout.androidaps.extensions.toStringShort
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
@ -72,26 +75,10 @@ class PersistentNotificationPlugin @Inject constructor(
|
|||
.toObservable(EventRefreshOverview::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventInitializationChanged::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
|
|
|
@ -328,7 +328,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
} else if (lastBG != null) {
|
||||
val agoMilliseconds = dateUtil.now() - lastBG.timestamp
|
||||
val agoMin = (agoMilliseconds / 60.0 / 1000.0).toInt()
|
||||
reply = rh.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + String.format(rh.gs(R.string.sms_minago), agoMin) + ", "
|
||||
reply = rh.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + rh.gs(R.string.sms_minago, agoMin) + ", "
|
||||
}
|
||||
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
|
||||
if (glucoseStatus != null) reply += rh.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "
|
||||
|
@ -348,7 +348,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
"DISABLE", "STOP" -> {
|
||||
if (loop.enabled) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_loopdisablereplywithcode), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_loopdisablereplywithcode, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
|
||||
override fun run() {
|
||||
|
@ -372,7 +372,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
"ENABLE", "START" -> {
|
||||
if (!loop.enabled) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_loopenablereplywithcode), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_loopenablereplywithcode, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
|
||||
override fun run() {
|
||||
|
@ -389,7 +389,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
|
||||
"STATUS" -> {
|
||||
val reply = if (loop.enabled) {
|
||||
if (loop.isSuspended) String.format(rh.gs(R.string.loopsuspendedfor), loop.minutesToEndOfSuspend())
|
||||
if (loop.isSuspended) rh.gs(R.string.loopsuspendedfor, loop.minutesToEndOfSuspend())
|
||||
else rh.gs(R.string.smscommunicator_loopisenabled)
|
||||
} else
|
||||
rh.gs(R.string.loopisdisabled)
|
||||
|
@ -399,7 +399,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
|
||||
"RESUME" -> {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_loopresumereplywithcode), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_loopresumereplywithcode, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||
override fun run() {
|
||||
|
@ -436,7 +436,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
return
|
||||
} else {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_suspendreplywithcode, duration, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, duration) {
|
||||
override fun run() {
|
||||
|
@ -515,7 +515,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
receivedSms.processed = true
|
||||
} else if ((divided.size == 2) && (divided[1].equals("CONNECT", ignoreCase = true))) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_pumpconnectwithcode), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_pumpconnectwithcode, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||
override fun run() {
|
||||
|
@ -548,7 +548,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
return
|
||||
} else {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_pumpdisconnectwithcode), duration, passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_pumpdisconnectwithcode, duration, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||
override fun run() {
|
||||
|
@ -601,7 +601,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.noprofile)))
|
||||
else {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_profilereplywithcode), list[pIndex - 1], percentage, passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_profilereplywithcode, list[pIndex - 1], percentage, passCode)
|
||||
receivedSms.processed = true
|
||||
val finalPercentage = percentage
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, list[pIndex - 1] as String, finalPercentage) {
|
||||
|
@ -627,7 +627,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
private fun processBASAL(divided: Array<String>, receivedSms: Sms) {
|
||||
if (divided[1].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(Locale.getDefault()) == "STOP") {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_basalstopreplywithcode, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||
override fun run() {
|
||||
|
@ -662,14 +662,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
else {
|
||||
tempBasalPct = constraintChecker.applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value()
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_basalpctreplywithcode, tempBasalPct, duration, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, tempBasalPct, duration) {
|
||||
override fun run() {
|
||||
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
|
||||
override fun run() {
|
||||
if (result.success) {
|
||||
var replyText = if (result.isPercent) String.format(rh.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(rh.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
|
||||
var replyText = if (result.isPercent) rh.gs(R.string.smscommunicator_tempbasalset_percent, result.percent, result.duration) else rh.gs(R.string.smscommunicator_tempbasalset, result.absolute, result.duration)
|
||||
replyText += "\n" + activePlugin.activePump.shortStatus(true)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
if (result.isPercent)
|
||||
|
@ -706,15 +706,15 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
else {
|
||||
tempBasal = constraintChecker.applyBasalConstraints(Constraint(tempBasal), profile).value()
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_basalreplywithcode, tempBasal, duration, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, tempBasal, duration) {
|
||||
override fun run() {
|
||||
commandQueue.tempBasalAbsolute(aDouble(), secondInteger(), true, profile, PumpSync.TemporaryBasalType.NORMAL, object : Callback() {
|
||||
override fun run() {
|
||||
if (result.success) {
|
||||
var replyText = if (result.isPercent) String.format(rh.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration)
|
||||
else String.format(rh.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
|
||||
var replyText = if (result.isPercent) rh.gs(R.string.smscommunicator_tempbasalset_percent, result.percent, result.duration)
|
||||
else rh.gs(R.string.smscommunicator_tempbasalset, result.absolute, result.duration)
|
||||
replyText += "\n" + activePlugin.activePump.shortStatus(true)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
if (result.isPercent)
|
||||
|
@ -743,7 +743,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
private fun processEXTENDED(divided: Array<String>, receivedSms: Sms) {
|
||||
if (divided[1].uppercase(Locale.getDefault()) == "CANCEL" || divided[1].uppercase(Locale.getDefault()) == "STOP") {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_extendedstopreplywithcode, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true) {
|
||||
override fun run() {
|
||||
|
@ -773,14 +773,14 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
if (extended == 0.0 || duration == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrongformat)))
|
||||
else {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_extendedreplywithcode, extended, duration, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, extended, duration) {
|
||||
override fun run() {
|
||||
commandQueue.extendedBolus(aDouble(), secondInteger(), object : Callback() {
|
||||
override fun run() {
|
||||
if (result.success) {
|
||||
var replyText = String.format(rh.gs(R.string.smscommunicator_extendedset), aDouble, duration)
|
||||
var replyText = rh.gs(R.string.smscommunicator_extendedset, aDouble, duration)
|
||||
if (config.APS) replyText += "\n" + rh.gs(R.string.loopsuspended)
|
||||
replyText += "\n" + activePlugin.activePump.shortStatus(true)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
|
@ -817,9 +817,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
} else if (bolus > 0.0) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = if (isMeal)
|
||||
String.format(rh.gs(R.string.smscommunicator_mealbolusreplywithcode), bolus, passCode)
|
||||
rh.gs(R.string.smscommunicator_mealbolusreplywithcode, bolus, passCode)
|
||||
else
|
||||
String.format(rh.gs(R.string.smscommunicator_bolusreplywithcode), bolus, passCode)
|
||||
rh.gs(R.string.smscommunicator_bolusreplywithcode, bolus, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, bolus) {
|
||||
override fun run() {
|
||||
|
@ -833,9 +833,9 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
override fun run() {
|
||||
if (resultSuccess) {
|
||||
var replyText = if (isMeal)
|
||||
String.format(rh.gs(R.string.smscommunicator_mealbolusdelivered), resultBolusDelivered)
|
||||
rh.gs(R.string.smscommunicator_mealbolusdelivered, resultBolusDelivered)
|
||||
else
|
||||
String.format(rh.gs(R.string.smscommunicator_bolusdelivered), resultBolusDelivered)
|
||||
rh.gs(R.string.smscommunicator_bolusdelivered, resultBolusDelivered)
|
||||
replyText += "\n" + activePlugin.activePump.shortStatus(true)
|
||||
lastRemoteBolusTime = dateUtil.now()
|
||||
if (isMeal) {
|
||||
|
@ -866,7 +866,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
val tt = if (currentProfile.units == GlucoseUnit.MMOL) {
|
||||
DecimalFormatter.to1Decimal(eatingSoonTT)
|
||||
} else DecimalFormatter.to0Decimal(eatingSoonTT)
|
||||
replyText += "\n" + String.format(rh.gs(R.string.smscommunicator_mealbolusdelivered_tt), tt, eatingSoonTTDuration)
|
||||
replyText += "\n" + rh.gs(R.string.smscommunicator_mealbolusdelivered_tt, tt, eatingSoonTTDuration)
|
||||
}
|
||||
}
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
|
@ -920,7 +920,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, rh.gs(R.string.wrongformat)))
|
||||
else {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_carbsreplywithcode), grams, dateUtil.timeString(time), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_carbsreplywithcode, grams, dateUtil.timeString(time), passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = true, grams, time) {
|
||||
override fun run() {
|
||||
|
@ -930,7 +930,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (result.success) {
|
||||
var replyText = String.format(rh.gs(R.string.smscommunicator_carbsset), anInteger)
|
||||
var replyText = rh.gs(R.string.smscommunicator_carbsset, anInteger)
|
||||
replyText += "\n" + activePlugin.activePump.shortStatus(true)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
uel.log(Action.CARBS, Sources.SMS, activePlugin.activePump.shortStatus(true) + ": " + rh.gs(R.string.smscommunicator_carbsset, anInteger),
|
||||
|
@ -956,7 +956,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
val isStop = divided[1].equals("STOP", ignoreCase = true) || divided[1].equals("CANCEL", ignoreCase = true)
|
||||
if (isMeal || isActivity || isHypo) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_temptargetwithcode), divided[1].uppercase(Locale.getDefault()), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_temptargetwithcode, divided[1].uppercase(Locale.getDefault()), passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
|
||||
override fun run() {
|
||||
|
@ -1009,7 +1009,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
val ttString = if (units == GlucoseUnit.MMOL) DecimalFormatter.to1Decimal(tt) else DecimalFormatter.to0Decimal(tt)
|
||||
val replyText = String.format(rh.gs(R.string.smscommunicator_tt_set), ttString, ttDuration)
|
||||
val replyText = rh.gs(R.string.smscommunicator_tt_set, ttString, ttDuration)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
uel.log(Action.TT, Sources.SMS,
|
||||
ValueWithUnit.fromGlucoseUnit(tt, units.asText),
|
||||
|
@ -1018,7 +1018,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
})
|
||||
} else if (isStop) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_temptargetcancel), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_temptargetcancel, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
|
||||
override fun run() {
|
||||
|
@ -1028,7 +1028,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
val replyText = String.format(rh.gs(R.string.smscommunicator_tt_canceled))
|
||||
val replyText = rh.gs(R.string.smscommunicator_tt_canceled)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
uel.log(Action.CANCEL_TT, Sources.SMS, rh.gs(R.string.smscommunicator_tt_canceled),
|
||||
ValueWithUnit.SimpleString(rh.gsNotLocalised(R.string.smscommunicator_tt_canceled)))
|
||||
|
@ -1043,12 +1043,12 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
|| divided[1].equals("DISABLE", ignoreCase = true))
|
||||
if (isStop) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_stopsmswithcode), passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_stopsmswithcode, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false) {
|
||||
override fun run() {
|
||||
sp.putBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
|
||||
val replyText = String.format(rh.gs(R.string.smscommunicator_stoppedsms))
|
||||
val replyText = rh.gs(R.string.smscommunicator_stoppedsms)
|
||||
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
|
||||
uel.log(Action.STOP_SMS, Sources.SMS, rh.gs(R.string.smscommunicator_stoppedsms),
|
||||
ValueWithUnit.SimpleString(rh.gsNotLocalised(R.string.smscommunicator_stoppedsms)))
|
||||
|
@ -1061,7 +1061,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
val cal = SafeParse.stringToDouble(divided[1])
|
||||
if (cal > 0.0) {
|
||||
val passCode = generatePassCode()
|
||||
val reply = String.format(rh.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode)
|
||||
val reply = rh.gs(R.string.smscommunicator_calibrationreplywithcode, cal, passCode)
|
||||
receivedSms.processed = true
|
||||
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(pumpCommand = false, cal) {
|
||||
override fun run() {
|
||||
|
@ -1127,7 +1127,7 @@ class SmsCommunicatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
private fun generatePassCode(): String =
|
||||
String.format(rh.gs(R.string.smscommunicator_code_from_authenticator_for), otp.name())
|
||||
rh.gs(R.string.smscommunicator_code_from_authenticator_for, otp.name())
|
||||
|
||||
private fun stripAccents(str: String): String {
|
||||
var s = str
|
||||
|
|
|
@ -31,7 +31,6 @@ import javax.inject.Inject
|
|||
class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
|
||||
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
|
||||
@Inject lateinit var otp: OneTimePassword
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package info.nightscout.androidaps.plugins.general.themes
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventThemeSwitch
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ThemeSwitcherPlugin @Inject constructor(
|
||||
injector: HasAndroidInjector,
|
||||
aapsLogger: AAPSLogger,
|
||||
rh: ResourceHelper,
|
||||
private val sp: SP,
|
||||
private val rxBus: RxBus,
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.neverVisible(true)
|
||||
.alwaysEnabled(true)
|
||||
.showInList(false)
|
||||
.pluginName(R.string.dst_plugin_name),
|
||||
aapsLogger, rh, injector
|
||||
) {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
override fun onStart() {
|
||||
compositeDisposable.add(rxBus.toObservable(EventPreferenceChange::class.java).subscribe {
|
||||
if (it.isChanged(rh, id = R.string.key_use_dark_mode)) {
|
||||
setThemeMode()
|
||||
rxBus.send(EventThemeSwitch())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun setThemeMode() {
|
||||
val mode = when (sp.getString(R.string.key_use_dark_mode, "dark")) {
|
||||
sp.getString(R.string.value_dark_theme, "dark") -> MODE_NIGHT_YES
|
||||
sp.getString(R.string.value_light_theme, "light") -> MODE_NIGHT_NO
|
||||
else -> MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
AppCompatDelegate.setDefaultNightMode(mode)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
compositeDisposable.dispose()
|
||||
}
|
||||
}
|
|
@ -111,7 +111,7 @@ class ActionStringHandler @Inject constructor(
|
|||
@Synchronized
|
||||
private fun handleInitiate(actionString: String) {
|
||||
//TODO: i18n
|
||||
Log.i("ActionStringHandler", "handleInitiate actionString=" + actionString)
|
||||
Log.i("ActionStringHandler", "handleInitiate actionString=$actionString")
|
||||
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
||||
lastBolusWizard = null
|
||||
var rTitle = rh.gs(R.string.confirm).uppercase()
|
||||
|
@ -640,10 +640,10 @@ class ActionStringHandler @Inject constructor(
|
|||
var msg = ""
|
||||
//check for validity
|
||||
if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
|
||||
msg += String.format(rh.gs(R.string.valueoutofrange), "Profile-Percentage") + "\n"
|
||||
msg += rh.gs(R.string.valueoutofrange, "Profile-Percentage") + "\n"
|
||||
}
|
||||
if (timeshift < 0 || timeshift > 23) {
|
||||
msg += String.format(rh.gs(R.string.valueoutofrange), "Profile-Timeshift") + "\n"
|
||||
msg += rh.gs(R.string.valueoutofrange, "Profile-Timeshift") + "\n"
|
||||
}
|
||||
val profile = profileFunction.getProfile()
|
||||
if (profile == null) {
|
||||
|
|
|
@ -95,7 +95,7 @@ class WearPlugin @Inject constructor(
|
|||
.toObservable(EventBolusRequested::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventBolusRequested ->
|
||||
val status = String.format(rh.gs(R.string.bolusrequested), event.amount)
|
||||
val status = rh.gs(R.string.bolusrequested, event.amount)
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
|
||||
intent.putExtra("progresspercent", 0)
|
||||
intent.putExtra("progressstatus", status)
|
||||
|
|
|
@ -120,7 +120,7 @@ class SendToDataLayerThread extends AsyncTask<DataMap,Void,Void> {
|
|||
}
|
||||
state = 0;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, logPrefix + "Got exception in sendToWear: " + e.toString());
|
||||
Log.e(TAG, logPrefix + "Got exception in sendToWear: " + e);
|
||||
} finally {
|
||||
lastlock = 0;
|
||||
lock.unlock();
|
||||
|
|
|
@ -46,9 +46,6 @@ import info.nightscout.androidaps.interfaces.Loop;
|
|||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.Profile;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
|
||||
|
@ -64,7 +61,11 @@ import info.nightscout.androidaps.utils.DefaultValueHelper;
|
|||
import info.nightscout.androidaps.utils.TrendCalculator;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard;
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.shared.sharedPreferences.SP;
|
||||
import info.nightscout.shared.weardata.WearUris;
|
||||
|
||||
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
@Inject public GlucoseStatusProvider glucoseStatusProvider;
|
||||
|
@ -95,21 +96,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
public static final String ACTION_CANCEL_NOTIFICATION = WatchUpdaterService.class.getName().concat(".CancelNotification");
|
||||
|
||||
private GoogleApiClient googleApiClient;
|
||||
public static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
|
||||
public static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
|
||||
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
|
||||
public static final String WEARABLE_CONFIRM_ACTIONSTRING_PATH = "/nightscout_watch_confirmactionstring";
|
||||
public static final String WEARABLE_INITIATE_ACTIONSTRING_PATH = "/nightscout_watch_initiateactionstring";
|
||||
|
||||
private static final String OPEN_SETTINGS_PATH = "/openwearsettings";
|
||||
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
||||
private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear";
|
||||
private static final String QUICK_WIZARD_PATH = "/send_quick_wizard";
|
||||
public static final String BASAL_DATA_PATH = "/nightscout_watch_basal";
|
||||
public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
||||
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
|
||||
public static final String ACTION_CHANGECONFIRMATION_REQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
|
||||
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||
|
||||
String TAG = "WatchUpdateService";
|
||||
|
||||
|
@ -259,21 +245,21 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
// Log.d(TAG, "onMessageRecieved: " + event);
|
||||
|
||||
if (wearIntegration()) {
|
||||
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_RESEND_PATH)) {
|
||||
resendData();
|
||||
}
|
||||
|
||||
if (event != null && event.getPath().equals(WEARABLE_CANCELBOLUS_PATH)) {
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_CANCELBOLUS_PATH)) {
|
||||
cancelBolus();
|
||||
}
|
||||
|
||||
if (event != null && event.getPath().equals(WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
|
||||
String actionstring = new String(event.getData());
|
||||
aapsLogger.debug(LTag.WEAR, "Wear: " + actionstring);
|
||||
rxBus.send(new EventWearInitiateAction(actionstring));
|
||||
}
|
||||
|
||||
if (event != null && event.getPath().equals(WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
|
||||
String actionstring = new String(event.getData());
|
||||
aapsLogger.debug(LTag.WEAR, "Wear Confirm: " + actionstring);
|
||||
rxBus.send(new EventWearConfirmAction(actionstring));
|
||||
|
@ -299,7 +285,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
final DataMap dataMap = dataMapSingleBG(lastBG, glucoseStatus);
|
||||
|
||||
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dataMap);
|
||||
(new SendToDataLayerThread(WearUris.WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dataMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -389,7 +375,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
dataMaps.add(dataMap);
|
||||
}
|
||||
entries.putDataMapArrayList("entries", dataMaps);
|
||||
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
|
||||
(new SendToDataLayerThread(WearUris.WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
|
||||
}
|
||||
sendBasals();
|
||||
sendStatus();
|
||||
|
@ -423,13 +409,12 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
double endBasalValue = beginBasalValue;
|
||||
|
||||
TemporaryBasal tb1 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
|
||||
TemporaryBasal tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime); //TODO for Adrian ... what's the meaning?
|
||||
TemporaryBasal tb2;
|
||||
double tb_before = beginBasalValue;
|
||||
double tb_amount = beginBasalValue;
|
||||
long tb_start = runningTime;
|
||||
|
||||
if (tb1 != null) {
|
||||
tb_before = beginBasalValue;
|
||||
Profile profileTB = profileFunction.getProfile(runningTime);
|
||||
if (profileTB != null) {
|
||||
tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB);
|
||||
|
@ -457,7 +442,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
|
||||
|
||||
if (tb1 == null && tb2 == null) {
|
||||
//no temp stays no temp
|
||||
; //no temp stays no temp
|
||||
|
||||
} else if (tb1 != null && tb2 == null) {
|
||||
//temp is over -> push it
|
||||
|
@ -529,7 +514,8 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
if (!predArray.isEmpty()) {
|
||||
for (GlucoseValueDataPoint bg : predArray) {
|
||||
if (bg.getData().getValue() < 40) continue;
|
||||
predictions.add(predictionMap(bg.getData().getTimestamp(), bg.getData().getValue(), bg.getPredictionColor()));
|
||||
predictions.add(predictionMap(bg.getData().getTimestamp(),
|
||||
bg.getData().getValue(), bg.color(null)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -540,7 +526,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
dm.putDataMapArrayList("temps", temps);
|
||||
dm.putDataMapArrayList("boluses", boluses);
|
||||
dm.putDataMapArrayList("predictions", predictions);
|
||||
(new SendToDataLayerThread(BASAL_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dm);
|
||||
(new SendToDataLayerThread(WearUris.BASAL_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dm);
|
||||
}
|
||||
|
||||
private DataMap tempDatamap(long startTime, double startBasal, long to, double toBasal, double amount) {
|
||||
|
@ -582,7 +568,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
private void sendNotification() {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(OPEN_SETTINGS_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.OPEN_SETTINGS_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
|
||||
|
@ -595,7 +581,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
private void sendBolusProgress(int progresspercent, String status) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(BOLUS_PROGRESS_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.BOLUS_PROGRESS_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("bolusProgress", "bolusProgress");
|
||||
|
@ -610,7 +596,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
private void sendActionConfirmationRequest(String title, String message, String actionstring) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(ACTION_CONFIRMATION_REQUEST_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CONFIRMATION_REQUEST_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("actionConfirmationRequest", "actionConfirmationRequest");
|
||||
|
@ -629,7 +615,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
private void sendChangeConfirmationRequest(String title, String message, String actionstring) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(ACTION_CHANGECONFIRMATION_REQUEST_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CHANGECONFIRMATION_REQUEST_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("changeConfirmationRequest", "changeConfirmationRequest");
|
||||
|
@ -648,7 +634,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
|
||||
private void sendCancelNotificationRequest(String actionstring) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(ACTION_CANCELNOTIFICATION_REQUEST_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CANCELNOTIFICATION_REQUEST_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("cancelNotificationRequest", "cancelNotificationRequest");
|
||||
|
@ -704,7 +690,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
openApsStatus = nsDeviceStatus.getOpenApsTimestamp();
|
||||
}
|
||||
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_STATUS_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.NEW_STATUS_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putString("externalStatusString", status);
|
||||
dataMapRequest.getDataMap().putString("iobSum", iobSum);
|
||||
|
@ -734,14 +720,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
int percentage = sp.getInt(R.string.key_boluswizard_percentage, 100);
|
||||
int maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
|
||||
double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.NEW_PREFERENCES_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_wear_control), wearcontrol);
|
||||
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_units_mgdl), mgdl);
|
||||
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_boluswizard_percentage), percentage);
|
||||
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_treatmentssafety_maxcarbs), maxCarbs);
|
||||
dataMapRequest.getDataMap().putDouble(rh.gs(R.string.key_treatmentssafety_maxbolus),maxBolus);
|
||||
dataMapRequest.getDataMap().putDouble(rh.gs(R.string.key_treatmentssafety_maxbolus), maxBolus);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
|
@ -753,14 +739,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
int size = quickWizard.size();
|
||||
ArrayList<DataMap> entities = new ArrayList<>();
|
||||
for(int i=0; i < size; i++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
QuickWizardEntry q = quickWizard.get(i);
|
||||
if (q.forDevice(QuickWizardEntry.DEVICE_WATCH)) {
|
||||
entities.add(quickMap(q));
|
||||
}
|
||||
}
|
||||
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(QUICK_WIZARD_PATH);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.QUICK_WIZARD_PATH);
|
||||
|
||||
DataMap dm = dataMapRequest.getDataMap();
|
||||
dm.putLong("timestamp", System.currentTimeMillis());
|
||||
|
@ -794,7 +780,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
return status;
|
||||
}
|
||||
|
||||
if (!((PluginBase)loop).isEnabled()) {
|
||||
if (!((PluginBase) loop).isEnabled()) {
|
||||
status += rh.gs(R.string.disabledloop) + "\n";
|
||||
lastLoopStatus = false;
|
||||
} else {
|
||||
|
|
|
@ -44,6 +44,9 @@ class ActivityGraph : GraphView {
|
|||
viewport.isXAxisBoundsManual = true
|
||||
viewport.setMinX(0.0)
|
||||
viewport.setMaxX((hours * 60).toDouble())
|
||||
viewport.isYAxisBoundsManual = true
|
||||
viewport.setMinY(0.0)
|
||||
viewport.setMaxY(0.01)
|
||||
gridLabelRenderer.numHorizontalLabels = (hours + 1).toInt()
|
||||
gridLabelRenderer.horizontalAxisTitle = "[min]"
|
||||
secondScale.addSeries(LineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.iob.iobCobCalculator
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.collection.LongSparseArray
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
|
@ -19,20 +18,19 @@ import info.nightscout.androidaps.extensions.convertedToAbsolute
|
|||
import info.nightscout.androidaps.extensions.iobCalc
|
||||
import info.nightscout.androidaps.extensions.toTemporaryBasal
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.workflow.CalculationWorkflow
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -57,12 +55,11 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
rh: ResourceHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val sensitivityOref1Plugin: SensitivityOref1Plugin,
|
||||
private val sensitivityAAPSPlugin: SensitivityAAPSPlugin,
|
||||
private val sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val dateUtil: DateUtil,
|
||||
private val repository: AppRepository
|
||||
private val repository: AppRepository,
|
||||
val overviewData: OverviewData,
|
||||
private val calculationWorkflow: CalculationWorkflow
|
||||
) : PluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
|
@ -81,7 +78,6 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
override var ads: AutosensDataStore = AutosensDataStore()
|
||||
|
||||
private val dataLock = Any()
|
||||
var stopCalculationTrigger = false
|
||||
private var thread: Thread? = null
|
||||
|
||||
override fun onStart() {
|
||||
|
@ -117,14 +113,6 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
resetDataAndRunCalculation("onEventPreferenceChange", event)
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
// EventAppInitialized
|
||||
disposable += rxBus
|
||||
.toObservable(EventAppInitialized::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe(
|
||||
{ event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), bgDataReload = true, limitDataToOldestAvailable = true, cause = event) },
|
||||
fabricPrivacy::logException
|
||||
)
|
||||
// EventNewHistoryData
|
||||
disposable += rxBus
|
||||
.toObservable(EventNewHistoryData::class.java)
|
||||
|
@ -138,10 +126,10 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
private fun resetDataAndRunCalculation(reason: String, event: Event?) {
|
||||
stopCalculation(reason)
|
||||
calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION,reason)
|
||||
clearCache()
|
||||
ads.reset()
|
||||
runCalculation(reason, System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event)
|
||||
calculationWorkflow.runCalculation(CalculationWorkflow.MAIN_CALCULATION,this, overviewData, reason, System.currentTimeMillis(), bgDataReload = false, limitDataToOldestAvailable = true, cause = event, runLoop = true)
|
||||
}
|
||||
|
||||
override fun clearCache() {
|
||||
|
@ -168,10 +156,9 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
return oldestTime
|
||||
}
|
||||
|
||||
fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long {
|
||||
override fun calculateDetectionStart(from: Long, limitDataToOldestAvailable: Boolean): Long {
|
||||
val profile = profileFunction.getProfile(from)
|
||||
var dia = Constants.defaultDIA
|
||||
if (profile != null) dia = profile.dia
|
||||
val dia = profile?.dia ?: Constants.defaultDIA
|
||||
val oldestDataAvailable = oldestDataAvailable()
|
||||
val getBGDataFrom: Long
|
||||
if (limitDataToOldestAvailable) {
|
||||
|
@ -302,11 +289,7 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
override fun getMealDataWithWaitingForCalculationFinish(): MealData {
|
||||
val result = MealData()
|
||||
val now = System.currentTimeMillis()
|
||||
val maxAbsorptionHours: Double = if (sensitivityAAPSPlugin.isEnabled() || sensitivityWeightedAveragePlugin.isEnabled()) {
|
||||
sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||
} else {
|
||||
sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||
}
|
||||
val maxAbsorptionHours: Double = activePlugin.activeSensitivity.maxAbsorptionHours()
|
||||
val absorptionTimeAgo = now - (maxAbsorptionHours * T.hours(1).msecs()).toLong()
|
||||
repository.getCarbsDataFromTimeToTimeExpanded(absorptionTimeAgo + 1, now, true)
|
||||
.blockingGet()
|
||||
|
@ -366,27 +349,6 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
return sb.toString()
|
||||
}
|
||||
|
||||
fun stopCalculation(from: String) {
|
||||
if (thread?.state != Thread.State.TERMINATED) {
|
||||
stopCalculationTrigger = true
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Stopping calculation thread: $from")
|
||||
while (thread != null && thread?.state != Thread.State.TERMINATED) {
|
||||
SystemClock.sleep(100)
|
||||
}
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Calculation thread stopped: $from")
|
||||
}
|
||||
}
|
||||
|
||||
fun runCalculation(from: String, end: Long, bgDataReload: Boolean, limitDataToOldestAvailable: Boolean, cause: Event?) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Starting calculation thread: " + from + " to " + dateUtil.dateAndTimeAndSecondsString(end))
|
||||
if (thread == null || thread?.state == Thread.State.TERMINATED) {
|
||||
thread =
|
||||
if (sensitivityOref1Plugin.isEnabled()) IobCobOref1Thread(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause)
|
||||
else IobCobThread(injector, this, from, end, bgDataReload, limitDataToOldestAvailable, cause)
|
||||
thread?.start()
|
||||
}
|
||||
}
|
||||
|
||||
// Limit rate of EventNewHistoryData
|
||||
private val historyWorker = Executors.newSingleThreadScheduledExecutor()
|
||||
private var scheduledHistoryPost: ScheduledFuture<*>? = null
|
||||
|
@ -428,7 +390,7 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
// When historical data is changed (coming from NS etc) finished calculations after this date must be invalidated
|
||||
private fun newHistoryData(oldDataTimestamp: Long, bgDataReload: Boolean, event: Event) {
|
||||
//log.debug("Locking onNewHistoryData");
|
||||
stopCalculation("onEventNewHistoryData")
|
||||
calculationWorkflow.stopCalculation(CalculationWorkflow.MAIN_CALCULATION,"onEventNewHistoryData")
|
||||
synchronized(dataLock) {
|
||||
|
||||
// clear up 5 min back for proper COB calculation
|
||||
|
@ -452,7 +414,7 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
}
|
||||
ads.newHistoryData(time, aapsLogger, dateUtil)
|
||||
}
|
||||
runCalculation(event.javaClass.simpleName, System.currentTimeMillis(), bgDataReload, true, event)
|
||||
calculationWorkflow.runCalculation(CalculationWorkflow.MAIN_CALCULATION,this, overviewData, event.javaClass.simpleName, System.currentTimeMillis(), bgDataReload, true, event, runLoop = true)
|
||||
//log.debug("Releasing onNewHistoryData");
|
||||
}
|
||||
|
||||
|
@ -574,17 +536,17 @@ class IobCobCalculatorPlugin @Inject constructor(
|
|||
override fun getTempBasalIncludingConvertedExtended(timestamp: Long): TemporaryBasal? {
|
||||
val tb = repository.getTemporaryBasalActiveAt(timestamp).blockingGet()
|
||||
if (tb is ValueWrapper.Existing) return tb.value
|
||||
return getConvertedExtended(timestamp);
|
||||
return getConvertedExtended(timestamp)
|
||||
}
|
||||
|
||||
override fun getTempBasalIncludingConvertedExtendedForRange(startTime: Long, endTime: Long, calculationStep: Long): Map<Long, TemporaryBasal?> {
|
||||
val tempBasals = HashMap<Long, TemporaryBasal?>();
|
||||
val tempBasals = HashMap<Long, TemporaryBasal?>()
|
||||
val tbs = repository.getTemporaryBasalsDataActiveBetweenTimeAndTime(startTime, endTime).blockingGet()
|
||||
for (t in startTime until endTime step calculationStep) {
|
||||
val tb = tbs.firstOrNull { basal -> basal.timestamp <= t && (basal.timestamp + basal.duration) > t }
|
||||
tempBasals[t] = tb ?: getConvertedExtended(t)
|
||||
}
|
||||
return tempBasals;
|
||||
return tempBasals
|
||||
}
|
||||
|
||||
override fun calculateAbsoluteIobFromBaseBasals(toTime: Long): IobTotal {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package info.nightscout.androidaps.plugins.iob.iobCobCalculator
|
||||
|
||||
import android.content.Context
|
||||
import android.os.PowerManager
|
||||
import android.os.SystemClock
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -12,9 +14,8 @@ import info.nightscout.androidaps.events.Event
|
|||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.extensions.target
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
|
@ -23,6 +24,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
|
|||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
|
@ -30,6 +32,9 @@ import info.nightscout.androidaps.utils.Profiler
|
|||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.workflow.CalculationWorkflow
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -38,15 +43,10 @@ import kotlin.math.max
|
|||
import kotlin.math.min
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
class IobCobOref1Thread internal constructor(
|
||||
private val injector: HasAndroidInjector,
|
||||
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance
|
||||
private val from: String,
|
||||
private val end: Long,
|
||||
private val bgDataReload: Boolean,
|
||||
private val limitDataToOldestAvailable: Boolean,
|
||||
private val cause: Event?
|
||||
) : Thread() {
|
||||
class IobCobOref1Worker(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
) : Worker(context, params) {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var sp: SP
|
||||
|
@ -62,48 +62,53 @@ class IobCobOref1Thread internal constructor(
|
|||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
private var mWakeLock: PowerManager.WakeLock? = null
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
@Inject lateinit var calculationWorkflow: CalculationWorkflow
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
mWakeLock = (context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, rh.gs(R.string.app_name) + ":iobCobThread")
|
||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
class IobCobOref1WorkerData(
|
||||
val injector: HasAndroidInjector,
|
||||
val iobCobCalculator: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance
|
||||
val from: String,
|
||||
val end: Long,
|
||||
val limitDataToOldestAvailable: Boolean,
|
||||
val cause: Event?
|
||||
)
|
||||
|
||||
override fun doWork(): Result {
|
||||
|
||||
val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as IobCobOref1WorkerData?
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
|
||||
val start = dateUtil.now()
|
||||
mWakeLock?.acquire(T.mins(10).msecs())
|
||||
try {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from")
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: ${data.from}")
|
||||
if (!profileFunction.isProfileValid("IobCobThread")) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): $from")
|
||||
return // app still initializing
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): ${data.from}")
|
||||
return Result.failure(workDataOf("Error" to "app still initializing"))
|
||||
}
|
||||
//log.debug("Locking calculateSensitivityData");
|
||||
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
||||
if (bgDataReload) {
|
||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus)
|
||||
iobCobCalculatorPlugin.clearCache()
|
||||
}
|
||||
val oldestTimeWithData = data.iobCobCalculator.calculateDetectionStart(data.end, data.limitDataToOldestAvailable)
|
||||
// work on local copy and set back when finished
|
||||
val ads = iobCobCalculatorPlugin.ads.clone()
|
||||
val ads = data.iobCobCalculator.ads.clone()
|
||||
val bucketedData = ads.bucketedData
|
||||
val autosensDataTable = ads.autosensDataTable
|
||||
if (bucketedData == null || bucketedData.size < 3) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
|
||||
return
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): ${data.from}")
|
||||
return Result.failure(workDataOf("Error" to "Aborting calculation thread (No bucketed data available): ${data.from}"))
|
||||
}
|
||||
val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp)
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime))
|
||||
var previous = autosensDataTable[prevDataTime]
|
||||
// start from oldest to be able sub cob
|
||||
for (i in bucketedData.size - 4 downTo 0) {
|
||||
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
||||
rxBus.send(EventIobCalculationProgress(progress, cause))
|
||||
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
||||
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
||||
return
|
||||
rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100 - (100.0 * i / bucketedData.size).toInt(), data.cause))
|
||||
if (isStopped) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): ${data.from}")
|
||||
return Result.failure(workDataOf("Error" to "Aborting calculation thread (trigger): ${data.from}"))
|
||||
}
|
||||
// check if data already exists
|
||||
var bgTime = bucketedData[i].timestamp
|
||||
|
@ -116,12 +121,12 @@ class IobCobOref1Thread internal constructor(
|
|||
}
|
||||
val profile = profileFunction.getProfile(bgTime)
|
||||
if (profile == null) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from")
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): ${data.from}")
|
||||
continue // profile not set yet
|
||||
}
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")")
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: ${data.from} ($i/${bucketedData.size})")
|
||||
val sens = profile.getIsfMgdl(bgTime)
|
||||
val autosensData = AutosensData(injector)
|
||||
val autosensData = AutosensData(data.injector)
|
||||
autosensData.time = bgTime
|
||||
if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList()
|
||||
|
||||
|
@ -136,7 +141,7 @@ class IobCobOref1Thread internal constructor(
|
|||
autosensData.bg = bg
|
||||
delta = bg - bucketedData[i + 1].value
|
||||
avgDelta = (bg - bucketedData[i + 3].value) / 3
|
||||
val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile)
|
||||
val iob = data.iobCobCalculator.calculateFromTreatmentsAndTemps(bgTime, profile)
|
||||
val bgi = -iob.activity * sens * 5
|
||||
val deviation = delta - bgi
|
||||
val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0
|
||||
|
@ -312,22 +317,27 @@ class IobCobOref1Thread internal constructor(
|
|||
if (min in 0..4 && hours % 2 == 0) autosensData.extraDeviation.add(0.0)
|
||||
previous = autosensData
|
||||
if (bgTime < dateUtil.now()) autosensDataTable.put(bgTime, autosensData)
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil))
|
||||
aapsLogger.debug(
|
||||
LTag.AUTOSENS,
|
||||
"Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(
|
||||
dateUtil
|
||||
)
|
||||
)
|
||||
val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime)
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity")
|
||||
autosensData.autosensResult = sensitivity
|
||||
aapsLogger.debug(LTag.AUTOSENS, autosensData.toString())
|
||||
}
|
||||
iobCobCalculatorPlugin.ads = ads
|
||||
data.iobCobCalculator.ads = ads
|
||||
Thread {
|
||||
SystemClock.sleep(1000)
|
||||
rxBus.send(EventAutosensCalculationFinished(cause))
|
||||
rxBus.send(EventAutosensCalculationFinished(data.cause))
|
||||
}.start()
|
||||
} finally {
|
||||
mWakeLock?.release()
|
||||
rxBus.send(EventIobCalculationProgress("", cause))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
||||
rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100, data.cause))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: ${data.from}")
|
||||
profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start)
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package info.nightscout.androidaps.plugins.iob.iobCobCalculator
|
||||
|
||||
import android.content.Context
|
||||
import android.os.PowerManager
|
||||
import android.os.SystemClock
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -10,9 +12,8 @@ import info.nightscout.androidaps.database.AppRepository
|
|||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
|
@ -21,6 +22,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData
|
|||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
||||
import info.nightscout.androidaps.receivers.DataWorker
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
|
@ -28,23 +30,20 @@ import info.nightscout.androidaps.utils.Profiler
|
|||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.workflow.CalculationWorkflow
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
class IobCobThread @Inject internal constructor(
|
||||
private val injector: HasAndroidInjector,
|
||||
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin, // cannot be injected : HistoryBrowser uses different instance
|
||||
private val from: String,
|
||||
private val end: Long,
|
||||
private val bgDataReload: Boolean,
|
||||
private val limitDataToOldestAvailable: Boolean,
|
||||
private val cause: Event?
|
||||
) : Thread() {
|
||||
class IobCobOrefWorker @Inject internal constructor(
|
||||
context: Context,
|
||||
params: WorkerParameters
|
||||
) : Worker(context, params) {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var sp: SP
|
||||
|
@ -60,48 +59,51 @@ class IobCobThread @Inject internal constructor(
|
|||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var repository: AppRepository
|
||||
|
||||
private var mWakeLock: PowerManager.WakeLock? = null
|
||||
@Inject lateinit var dataWorker: DataWorker
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
mWakeLock = (context.applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, rh.gs(R.string.app_name) + ":iobCobThread")
|
||||
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
class IobCobOrefWorkerData(
|
||||
val injector: HasAndroidInjector,
|
||||
val iobCobCalculatorPlugin: IobCobCalculator, // cannot be injected : HistoryBrowser uses different instance
|
||||
val from: String,
|
||||
val end: Long,
|
||||
val limitDataToOldestAvailable: Boolean,
|
||||
val cause: Event?
|
||||
)
|
||||
|
||||
override fun doWork(): Result {
|
||||
val data = dataWorker.pickupObject(inputData.getLong(DataWorker.STORE_KEY, -1)) as IobCobOrefWorkerData?
|
||||
?: return Result.failure(workDataOf("Error" to "missing input data"))
|
||||
|
||||
val start = dateUtil.now()
|
||||
mWakeLock?.acquire(T.mins(10).msecs())
|
||||
try {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: $from")
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread started: ${data.from}")
|
||||
if (!profileFunction.isProfileValid("IobCobThread")) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): $from")
|
||||
return // app still initializing
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No profile): ${data.from}")
|
||||
return Result.failure(workDataOf("Error" to "app still initializing"))
|
||||
}
|
||||
//log.debug("Locking calculateSensitivityData");
|
||||
val oldestTimeWithData = iobCobCalculatorPlugin.calculateDetectionStart(end, limitDataToOldestAvailable)
|
||||
if (bgDataReload) {
|
||||
iobCobCalculatorPlugin.ads.loadBgData(end, repository, aapsLogger, dateUtil, rxBus)
|
||||
iobCobCalculatorPlugin.clearCache()
|
||||
}
|
||||
val oldestTimeWithData = data.iobCobCalculatorPlugin.calculateDetectionStart(data.end, data.limitDataToOldestAvailable)
|
||||
// work on local copy and set back when finished
|
||||
val ads = iobCobCalculatorPlugin.ads.clone()
|
||||
val ads = data.iobCobCalculatorPlugin.ads.clone()
|
||||
val bucketedData = ads.bucketedData
|
||||
val autosensDataTable = ads.autosensDataTable
|
||||
if (bucketedData == null || bucketedData.size < 3) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): $from")
|
||||
return
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (No bucketed data available): ${data.from}")
|
||||
return Result.failure(workDataOf("Error" to "Aborting calculation thread (No bucketed data available): ${data.from}"))
|
||||
}
|
||||
val prevDataTime = ads.roundUpTime(bucketedData[bucketedData.size - 3].timestamp)
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Prev data time: " + dateUtil.dateAndTimeString(prevDataTime))
|
||||
var previous = autosensDataTable[prevDataTime]
|
||||
// start from oldest to be able sub cob
|
||||
for (i in bucketedData.size - 4 downTo 0) {
|
||||
val progress = i.toString() + if (buildHelper.isDev()) " ($from)" else ""
|
||||
rxBus.send(EventIobCalculationProgress(progress, cause))
|
||||
if (iobCobCalculatorPlugin.stopCalculationTrigger) {
|
||||
iobCobCalculatorPlugin.stopCalculationTrigger = false
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): $from")
|
||||
return
|
||||
rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100 - (100.0 * i / bucketedData.size).toInt(), data.cause))
|
||||
if (isStopped) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (trigger): ${data.from}")
|
||||
return Result.failure(workDataOf("Error" to "Aborting calculation thread (trigger): ${data.from}"))
|
||||
}
|
||||
// check if data already exists
|
||||
var bgTime = bucketedData[i].timestamp
|
||||
|
@ -114,12 +116,12 @@ class IobCobThread @Inject internal constructor(
|
|||
}
|
||||
val profile = profileFunction.getProfile(bgTime)
|
||||
if (profile == null) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): $from")
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Aborting calculation thread (no profile): ${data.from}")
|
||||
continue // profile not set yet
|
||||
}
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: " + from + " (" + i + "/" + bucketedData.size + ")")
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Processing calculation thread: ${data.from} ($i/${bucketedData.size})")
|
||||
val sens = profile.getIsfMgdl(bgTime)
|
||||
val autosensData = AutosensData(injector)
|
||||
val autosensData = AutosensData(data.injector)
|
||||
autosensData.time = bgTime
|
||||
if (previous != null) autosensData.activeCarbsList = previous.cloneCarbsList() else autosensData.activeCarbsList = ArrayList()
|
||||
|
||||
|
@ -134,7 +136,7 @@ class IobCobThread @Inject internal constructor(
|
|||
autosensData.bg = bg
|
||||
delta = bg - bucketedData[i + 1].value
|
||||
avgDelta = (bg - bucketedData[i + 3].value) / 3
|
||||
val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile)
|
||||
val iob = data.iobCobCalculatorPlugin.calculateFromTreatmentsAndTemps(bgTime, profile)
|
||||
val bgi = -iob.activity * sens * 5
|
||||
val deviation = delta - bgi
|
||||
val avgDeviation = ((avgDelta - bgi) * 1000).roundToLong() / 1000.0
|
||||
|
@ -158,7 +160,7 @@ class IobCobThread @Inject internal constructor(
|
|||
if (ad == null) {
|
||||
aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString())
|
||||
aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString())
|
||||
//aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
|
||||
//aapsLogger.debug(LTag.AUTOSENS, data.iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
|
||||
val notification = Notification(Notification.SEND_LOGFILES, rh.gs(R.string.sendlogfiles), Notification.LOW)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
sp.putBoolean("log_AUTOSENS", true)
|
||||
|
@ -181,7 +183,7 @@ class IobCobThread @Inject internal constructor(
|
|||
fabricPrivacy.logException(e)
|
||||
aapsLogger.debug(autosensDataTable.toString())
|
||||
aapsLogger.debug(bucketedData.toString())
|
||||
//aapsLogger.debug(iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
|
||||
//aapsLogger.debug(data.iobCobCalculatorPlugin.getBgReadingsDataTable().toString())
|
||||
val notification = Notification(Notification.SEND_LOGFILES, rh.gs(R.string.sendlogfiles), Notification.LOW)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
sp.putBoolean("log_AUTOSENS", true)
|
||||
|
@ -258,22 +260,27 @@ class IobCobThread @Inject internal constructor(
|
|||
}
|
||||
previous = autosensData
|
||||
if (bgTime < dateUtil.now()) autosensDataTable.put(bgTime, autosensData)
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(dateUtil))
|
||||
aapsLogger.debug(
|
||||
LTag.AUTOSENS,
|
||||
"Running detectSensitivity from: " + dateUtil.dateAndTimeString(oldestTimeWithData) + " to: " + dateUtil.dateAndTimeString(bgTime) + " lastDataTime:" + ads.lastDataTime(
|
||||
dateUtil
|
||||
)
|
||||
)
|
||||
val sensitivity = activePlugin.activeSensitivity.detectSensitivity(ads, oldestTimeWithData, bgTime)
|
||||
aapsLogger.debug(LTag.AUTOSENS, "Sensitivity result: $sensitivity")
|
||||
autosensData.autosensResult = sensitivity
|
||||
aapsLogger.debug(LTag.AUTOSENS, autosensData.toString())
|
||||
}
|
||||
iobCobCalculatorPlugin.ads = ads
|
||||
data.iobCobCalculatorPlugin.ads = ads
|
||||
Thread {
|
||||
SystemClock.sleep(1000)
|
||||
rxBus.send(EventAutosensCalculationFinished(cause))
|
||||
rxBus.send(EventAutosensCalculationFinished(data.cause))
|
||||
}.start()
|
||||
} finally {
|
||||
mWakeLock?.release()
|
||||
rxBus.send(EventIobCalculationProgress("", cause))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: $from")
|
||||
rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100, data.cause))
|
||||
aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: ${data.from}")
|
||||
profiler.log(LTag.AUTOSENS, "IobCobThread", start)
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.iob.iobCobCalculator.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.workflow.CalculationWorkflow
|
||||
|
||||
class EventIobCalculationProgress(val progress: String, val cause: Event?) : Event()
|
||||
class EventIobCalculationProgress(val pass: CalculationWorkflow.ProgressData, val progressPct: Int, val cause: Event?) : Event()
|
|
@ -9,15 +9,18 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.SingleFragmentActivity
|
||||
import info.nightscout.androidaps.data.ProfileSealed
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.databinding.LocalprofileFragmentBinding
|
||||
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
|
||||
import info.nightscout.androidaps.extensions.toVisibility
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
|
@ -29,6 +32,7 @@ import info.nightscout.androidaps.utils.DecimalFormatter
|
|||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.HardLimits
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.ui.TimeListEdit
|
||||
|
@ -49,14 +53,15 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
|
||||
@Inject lateinit var hardLimits: HardLimits
|
||||
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
private var inMenu = false
|
||||
private var queryingProtection = false
|
||||
private var basalView: TimeListEdit? = null
|
||||
// private var spinner: SpinnerHelper? = null
|
||||
|
||||
private val save = Runnable {
|
||||
doEdit()
|
||||
|
@ -88,8 +93,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
|
||||
private var _binding: LocalprofileFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
@ -99,31 +103,20 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
// activate DIA tab
|
||||
processVisibilityOnClick(binding.diaTab)
|
||||
binding.diaPlaceholder.visibility = View.VISIBLE
|
||||
// setup listeners
|
||||
binding.diaTab.setOnClickListener {
|
||||
processVisibilityOnClick(it)
|
||||
binding.diaPlaceholder.visibility = View.VISIBLE
|
||||
}
|
||||
binding.icTab.setOnClickListener {
|
||||
processVisibilityOnClick(it)
|
||||
binding.ic.visibility = View.VISIBLE
|
||||
}
|
||||
binding.isfTab.setOnClickListener {
|
||||
processVisibilityOnClick(it)
|
||||
binding.isf.visibility = View.VISIBLE
|
||||
}
|
||||
binding.basalTab.setOnClickListener {
|
||||
processVisibilityOnClick(it)
|
||||
binding.basal.visibility = View.VISIBLE
|
||||
}
|
||||
binding.targetTab.setOnClickListener {
|
||||
processVisibilityOnClick(it)
|
||||
binding.target.visibility = View.VISIBLE
|
||||
}
|
||||
binding.dia.editText?.id?.let { binding.diaLabel.labelFor = it }
|
||||
val parentClass = this.activity?.let { it::class.java }
|
||||
inMenu = parentClass == SingleFragmentActivity::class.java
|
||||
updateProtectedUi()
|
||||
processVisibility(0)
|
||||
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
processVisibility(tab.position)
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab) {}
|
||||
override fun onTabReselected(tab: TabLayout.Tab) {}
|
||||
})
|
||||
binding.diaLabel.labelFor = binding.dia.editTextId
|
||||
binding.unlock.setOnClickListener { queryProtection() }
|
||||
}
|
||||
|
||||
fun build() {
|
||||
|
@ -222,7 +215,6 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
)
|
||||
}
|
||||
|
||||
// Spinner
|
||||
context?.let { context ->
|
||||
val profileList: ArrayList<CharSequence> = localProfilePlugin.profile?.getProfileList() ?: ArrayList()
|
||||
binding.profileList.setAdapter(ArrayAdapter(context, R.layout.spinner_centered, profileList))
|
||||
|
@ -301,7 +293,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
|
||||
binding.profileswitch.setOnClickListener {
|
||||
ProfileSwitchDialog()
|
||||
.also { it.arguments = Bundle().also { bundle -> bundle.putInt("profileIndex", localProfilePlugin.currentProfileIndex) } }
|
||||
.also { it.arguments = Bundle().also { bundle -> bundle.putString("profileName", localProfilePlugin.currentProfile()?.name) } }
|
||||
.show(childFragmentManager, "ProfileSwitchDialog")
|
||||
}
|
||||
|
||||
|
@ -329,6 +321,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (inMenu) queryProtection() else updateProtectedUi()
|
||||
disposable += rxBus
|
||||
.toObservable(EventLocalProfileChanged::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
|
@ -366,7 +359,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
val isValid = localProfilePlugin.isValidEditState(activity)
|
||||
val isEdited = localProfilePlugin.isEdited
|
||||
if (isValid) {
|
||||
this.view?.setBackgroundColor(rh.gc(R.color.ok_background))
|
||||
this.view?.setBackgroundColor(rh.gac(context, R.attr.okBackgroundColor))
|
||||
binding.profileList.isEnabled = true
|
||||
|
||||
if (isEdited) {
|
||||
|
@ -378,7 +371,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
binding.save.visibility = View.GONE
|
||||
}
|
||||
} else {
|
||||
this.view?.setBackgroundColor(rh.gc(R.color.error_background))
|
||||
this.view?.setBackgroundColor(rh.gac(context, R.attr.errorBackgroundColor))
|
||||
binding.profileList.isEnabled = false
|
||||
binding.profileswitch.visibility = View.GONE
|
||||
binding.save.visibility = View.GONE //don't save an invalid profile
|
||||
|
@ -392,17 +385,28 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun processVisibilityOnClick(selected: View) {
|
||||
binding.diaTab.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.icTab.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.isfTab.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.basalTab.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
binding.targetTab.setBackgroundColor(rh.gc(R.color.defaultbackground))
|
||||
selected.setBackgroundColor(rh.gc(R.color.tabBgColorSelected))
|
||||
binding.diaPlaceholder.visibility = View.GONE
|
||||
binding.ic.visibility = View.GONE
|
||||
binding.isf.visibility = View.GONE
|
||||
binding.basal.visibility = View.GONE
|
||||
binding.target.visibility = View.GONE
|
||||
private fun processVisibility(position: Int) {
|
||||
binding.diaPlaceholder.visibility = (position == 0).toVisibility()
|
||||
binding.ic.visibility = (position == 1).toVisibility()
|
||||
binding.isf.visibility = (position == 2).toVisibility()
|
||||
binding.basal.visibility = (position == 3).toVisibility()
|
||||
binding.target.visibility = (position == 4).toVisibility()
|
||||
}
|
||||
|
||||
private fun updateProtectedUi() {
|
||||
val isLocked = protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES)
|
||||
binding.mainLayout.visibility = isLocked.not().toVisibility()
|
||||
binding.unlock.visibility = isLocked.toVisibility()
|
||||
}
|
||||
|
||||
private fun queryProtection() {
|
||||
val isLocked = protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES)
|
||||
if (isLocked && !queryingProtection) {
|
||||
activity?.let { activity ->
|
||||
queryingProtection = true
|
||||
val doUpdate = { activity.runOnUiThread { queryingProtection = false; updateProtectedUi() } }
|
||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, doUpdate, doUpdate, doUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,10 +52,6 @@ class VirtualPumpFragment : DaggerFragment() {
|
|||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
|
|
@ -137,6 +137,8 @@ class SensitivityAAPSPlugin @Inject constructor(
|
|||
return output
|
||||
}
|
||||
|
||||
override fun maxAbsorptionHours(): Double = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||
|
||||
override val id: SensitivityType
|
||||
get() = SensitivityType.SENSITIVITY_AAPS
|
||||
|
||||
|
|
|
@ -53,8 +53,6 @@ class SensitivityOref1Plugin @Inject constructor(
|
|||
) {
|
||||
|
||||
override fun detectSensitivity(ads: AutosensDataStore, fromTime: Long, toTime: Long): AutosensResult {
|
||||
// todo this method is called from the IobCobCalculatorPlugin, which leads to a circular
|
||||
// dependency, this should be avoided
|
||||
val profile = profileFunction.getProfile()
|
||||
if (profile == null) {
|
||||
aapsLogger.error("No profile")
|
||||
|
@ -204,6 +202,8 @@ class SensitivityOref1Plugin @Inject constructor(
|
|||
return output
|
||||
}
|
||||
|
||||
override fun maxAbsorptionHours(): Double = sp.getDouble(R.string.key_absorption_cutoff, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||
|
||||
override fun configuration(): JSONObject {
|
||||
val c = JSONObject()
|
||||
try {
|
||||
|
|
|
@ -157,6 +157,8 @@ class SensitivityWeightedAveragePlugin @Inject constructor(
|
|||
return output
|
||||
}
|
||||
|
||||
override fun maxAbsorptionHours(): Double = sp.getDouble(R.string.key_absorption_maxtime, Constants.DEFAULT_MAX_ABSORPTION_TIME)
|
||||
|
||||
override val id: SensitivityType
|
||||
get() = SensitivityType.SENSITIVITY_WEIGHTED
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package info.nightscout.androidaps.plugins.source
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.util.SparseArray
|
||||
import android.view.*
|
||||
import androidx.core.util.forEach
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.android.support.DaggerFragment
|
||||
|
@ -26,6 +25,7 @@ import info.nightscout.androidaps.interfaces.PluginBase
|
|||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.utils.ActionModeHelper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -54,11 +54,10 @@ class BGSourceFragment : DaggerFragment() {
|
|||
|
||||
private val disposable = CompositeDisposable()
|
||||
private val millsToThePast = T.hours(36).msecs()
|
||||
|
||||
private lateinit var actionHelper: ActionModeHelper<GlucoseValue>
|
||||
private var _binding: BgsourceFragmentBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
// This property is only valid between onCreateView and onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||
|
@ -66,6 +65,10 @@ class BGSourceFragment : DaggerFragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
actionHelper = ActionModeHelper(rh, activity)
|
||||
actionHelper.setUpdateListHandler { binding.recyclerview.adapter?.notifyDataSetChanged() }
|
||||
actionHelper.setOnRemoveHandler { removeSelected(it) }
|
||||
setHasOptionsMenu(actionHelper.inMenu)
|
||||
|
||||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||
|
@ -94,10 +97,21 @@ class BGSourceFragment : DaggerFragment() {
|
|||
|
||||
@Synchronized
|
||||
override fun onPause() {
|
||||
actionHelper.finish()
|
||||
disposable.clear()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
actionHelper.onCreateOptionsMenu(menu, inflater)
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
actionHelper.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
@ -105,6 +119,9 @@ class BGSourceFragment : DaggerFragment() {
|
|||
_binding = null
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) =
|
||||
actionHelper.onOptionsItemSelected(item)
|
||||
|
||||
inner class RecyclerViewAdapter internal constructor(private var glucoseValues: List<GlucoseValue>) : RecyclerView.Adapter<RecyclerViewAdapter.GlucoseValuesViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): GlucoseValuesViewHolder {
|
||||
|
@ -116,58 +133,83 @@ class BGSourceFragment : DaggerFragment() {
|
|||
val glucoseValue = glucoseValues[position]
|
||||
holder.binding.ns.visibility = (glucoseValue.interfaceIDs.nightscoutId != null).toVisibility()
|
||||
holder.binding.invalid.visibility = (!glucoseValue.isValid).toVisibility()
|
||||
val sameDayPrevious = position > 0 && dateUtil.isSameDay(glucoseValue.timestamp, glucoseValues[position-1].timestamp)
|
||||
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
|
||||
holder.binding.date.text = dateUtil.dateString(glucoseValue.timestamp)
|
||||
val newDay = position == 0 || !dateUtil.isSameDay(glucoseValue.timestamp, glucoseValues[position - 1].timestamp)
|
||||
holder.binding.date.visibility = newDay.toVisibility()
|
||||
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(glucoseValue.timestamp, rh) else ""
|
||||
holder.binding.time.text = dateUtil.timeString(glucoseValue.timestamp)
|
||||
holder.binding.value.text = glucoseValue.valueToUnitsString(profileFunction.getUnits())
|
||||
holder.binding.direction.setImageResource(glucoseValue.trendArrow.directionToIcon())
|
||||
holder.binding.remove.tag = glucoseValue
|
||||
if (position > 0) {
|
||||
val previous = glucoseValues[position - 1]
|
||||
val diff = previous.timestamp - glucoseValue.timestamp
|
||||
if (diff < T.secs(20).msecs())
|
||||
holder.binding.root.setBackgroundColor(rh.gc(R.color.errorAlertBackground))
|
||||
holder.binding.root.setBackgroundColor(rh.gac(context, R.attr.bgsourceError))
|
||||
}
|
||||
|
||||
holder.binding.root.setOnLongClickListener {
|
||||
if (actionHelper.startRemove()) {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, glucoseValue, holder.binding.cbRemove.isChecked)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
false
|
||||
}
|
||||
holder.binding.root.setOnClickListener {
|
||||
if (actionHelper.isRemoving) {
|
||||
holder.binding.cbRemove.toggle()
|
||||
actionHelper.updateSelection(position, glucoseValue, holder.binding.cbRemove.isChecked)
|
||||
}
|
||||
}
|
||||
holder.binding.cbRemove.setOnCheckedChangeListener { _, value ->
|
||||
actionHelper.updateSelection(position, glucoseValue, value)
|
||||
}
|
||||
holder.binding.cbRemove.isChecked = actionHelper.isSelected(position)
|
||||
holder.binding.cbRemove.visibility = actionHelper.isRemoving.toVisibility()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = glucoseValues.size
|
||||
override fun getItemCount() = glucoseValues.size
|
||||
|
||||
inner class GlucoseValuesViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
val binding = BgsourceItemBinding.bind(view)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
binding.remove.paintFlags = binding.remove.paintFlags or Paint.UNDERLINE_TEXT_FLAG
|
||||
binding.remove.setOnClickListener { v: View ->
|
||||
val glucoseValue = v.tag as GlucoseValue
|
||||
activity?.let { activity ->
|
||||
val text = dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits())
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), text, Runnable {
|
||||
val source = when ((activePlugin.activeBgSource as PluginBase).pluginDescription.pluginName) {
|
||||
R.string.dexcom_app_patched -> Sources.Dexcom
|
||||
R.string.eversense -> Sources.Eversense
|
||||
R.string.Glimp -> Sources.Glimp
|
||||
R.string.MM640g -> Sources.MM640g
|
||||
R.string.nsclientbg -> Sources.NSClientSource
|
||||
R.string.poctech -> Sources.PocTech
|
||||
R.string.tomato -> Sources.Tomato
|
||||
R.string.glunovo -> Sources.Glunovo
|
||||
R.string.xdrip -> Sources.Xdrip
|
||||
else -> Sources.Unknown
|
||||
}
|
||||
uel.log(
|
||||
Action.BG_REMOVED, source,
|
||||
ValueWithUnit.Timestamp(glucoseValue.timestamp)
|
||||
)
|
||||
repository.runTransactionForResult(InvalidateGlucoseValueTransaction(glucoseValue.id))
|
||||
.doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating BG value", it) }
|
||||
.blockingGet()
|
||||
.also { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bg $it") } }
|
||||
})
|
||||
private fun getConfirmationText(selectedItems: SparseArray<GlucoseValue>): String {
|
||||
if (selectedItems.size() == 1) {
|
||||
val glucoseValue = selectedItems.valueAt(0)
|
||||
return dateUtil.dateAndTimeString(glucoseValue.timestamp) + "\n" + glucoseValue.valueToUnitsString(profileFunction.getUnits())
|
||||
}
|
||||
return rh.gs(R.string.confirm_remove_multiple_items, selectedItems.size())
|
||||
}
|
||||
|
||||
private fun removeSelected(selectedItems: SparseArray<GlucoseValue>) {
|
||||
activity?.let { activity ->
|
||||
OKDialog.showConfirmation(activity, rh.gs(R.string.removerecord), getConfirmationText(selectedItems), Runnable {
|
||||
selectedItems.forEach { _, glucoseValue ->
|
||||
val source = when ((activePlugin.activeBgSource as PluginBase).pluginDescription.pluginName) {
|
||||
R.string.dexcom_app_patched -> Sources.Dexcom
|
||||
R.string.eversense -> Sources.Eversense
|
||||
R.string.Glimp -> Sources.Glimp
|
||||
R.string.MM640g -> Sources.MM640g
|
||||
R.string.nsclientbg -> Sources.NSClientSource
|
||||
R.string.poctech -> Sources.PocTech
|
||||
R.string.tomato -> Sources.Tomato
|
||||
R.string.glunovo -> Sources.Glunovo
|
||||
R.string.xdrip -> Sources.Xdrip
|
||||
else -> Sources.Unknown
|
||||
}
|
||||
uel.log(
|
||||
Action.BG_REMOVED, source,
|
||||
ValueWithUnit.Timestamp(glucoseValue.timestamp)
|
||||
)
|
||||
repository.runTransactionForResult(InvalidateGlucoseValueTransaction(glucoseValue.id))
|
||||
.doOnError { aapsLogger.error(LTag.DATABASE, "Error while invalidating BG value", it) }
|
||||
.blockingGet()
|
||||
.also { result -> result.invalidated.forEach { aapsLogger.debug(LTag.DATABASE, "Invalidated bg $it") } }
|
||||
}
|
||||
}
|
||||
actionHelper.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue