diff --git a/app/build.gradle b/app/build.gradle index c24cc57c18..f7513468c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,7 +105,7 @@ android { defaultConfig { multiDexEnabled true versionCode 1500 - version "3.1.0.2-dev-a" + version "3.1.0.3-dev-a" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"' buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"' diff --git a/app/src/main/assets/OpenAPSSMBDynamicISF/determine-basal.js b/app/src/main/assets/OpenAPSSMBDynamicISF/determine-basal.js index 24b8c29718..f3ff906aac 100644 --- a/app/src/main/assets/OpenAPSSMBDynamicISF/determine-basal.js +++ b/app/src/main/assets/OpenAPSSMBDynamicISF/determine-basal.js @@ -203,206 +203,97 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ // 80 mg/dL with low_temptarget_lowers_sensitivity would give 1.5x basal, but is limited to autosens_max (1.2x by default) } + //********************************************************************************* + //** Start of Dynamic ISF code for predictions ** + //********************************************************************************* - var profile_sens = round(profile.sens,1) - var sens = profile.sens; + console.error("---------------------------------------------------------"); + console.error( " Dynamic ISF version Beta 1.6.5 "); + console.error("---------------------------------------------------------"); - var now = new Date().getHours(); - if (now < 1){ - now = 1;} - else { - console.error("Time now is "+now+"; "); - } - //********************************************************************************* - //** Start of Dynamic ISF code for predictions ** - //********************************************************************************* + var variable_sens = profile.variable_sens; + var TDD = profile.TDD; + var insulinDivisor = profile.insulinDivisor; - console.error("---------------------------------------------------------"); - console.error( " Dynamic ISF version Beta 1.6.5 "); - console.error("---------------------------------------------------------"); + //********************************************************************************* + //** End of Dynamic ISF code for predictions ** + //********************************************************************************* - if (meal_data.TDDAIMI7){ - var tdd7 = meal_data.TDDAIMI7; - } - else{ - var tdd7 = ((basal * 12)*100)/21; - } - console.error("7-day average TDD is: " +tdd7+ "; "); - - 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); - - var tdd1 = meal_data.TDDAIMI1; - var tdd_4 = meal_data.TDDLast4; - var tdd8to4 = meal_data.TDD4to8; - var tdd_last8_wt = ( ( ( 1.4 * tdd_4) + ( 0.6 * tdd8to4) ) * 3 ); - - console.error("Rolling 8 hours weight average: "+tdd_last8_wt+"; "); - console.error("1-day average TDD is: "+tdd1+"; "); - console.error("7-day average TDD is: " +tdd7+ "; "); - - //TDD = ( tdd_last8_wt * 0.6) + ( tdd7 * 0.4 ); - - var TDD = ( tdd_last8_wt * 0.33 ) + ( tdd7 * 0.34 ) + (tdd1 * 0.33); - console.log("TDD = " +TDD+ " using average of 7-day, 1-day and weighted 8hr average"); - - - //var ins_val = 75; - var insulin = profile.insulinType; - console.log("Insulin Peak = "+profile.insulinPeak+"; "); - //console.log("Initial insulin value for ISF: "+ins_val+"; "); - //console.log("Current value for insulin: "+insulin+"; "); - - var ins_val; - if (profile.insulinPeak > 65) { // lyumjev peak: 45 - ins_val = 55; - } else if (profile.insulinPeak > 50 ){ // ultra rapid peak: 55 - ins_val = 65; + 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 { - ins_val = 75; // rapid peak: 75 + console.log("Basal unchanged: "+basal+"; "); } - console.log("For "+profile.insulinType+" (insulin peak: "+profile.insulinPeak+") divisor is: "+ins_val+"; "); + } - console.log("Insulin value for ISF based on profile: "+ins_val+"; "); - - var dynISFadjust = profile.DynISFAdjust; - dynISFadjust = ( dynISFadjust / 100 ); - TDD = ( dynISFadjust * TDD ); - - var variable_sens = 1800 / ( TDD * (Math.log(( bg / ins_val ) + 1 ) ) ); - - 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 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 = ( meal_data.TDD24 / 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+"; "); + // 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("Autosens disabled. Basal unchanged: "+basal+"; "); + console.log("target_bg from "+target_bg+" to "+new_target_bg+"; "); } + target_bg = new_target_bg; } + } - // 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; - } - } + 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 === 'undefined' ) { - rT.error ='Error: iob_data undefined. '; - return rT; - } + if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' ) { + rT.error ='Error: iob_data missing some property. '; + 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])); - } + var tick; - if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' ) { - rT.error ='Error: iob_data missing some property. '; - return rT; - } + 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 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); - - - console.error("; CR:",profile.carb_ratio); + var sens = variable_sens // compare currenttemp to iob_data.lastTemp and cancel temp if they don't match var lastTempAge; @@ -413,7 +304,7 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } //console.error("currenttemp:",currenttemp,"lastTemp:",JSON.stringify(iob_data.lastTemp),"lastTempAge:",lastTempAge,"m"); var tempModulus = (lastTempAge + currenttemp.duration) % 30; - console.error("currenttemp:",currenttemp,"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m"); + console.error("currenttemp:",round(currenttemp.rate,2),"lastTempAge:",lastTempAge,"m","tempModulus:",tempModulus,"m"); rT.temp = 'absolute'; rT.deliverAt = deliverAt; if ( microBolusAllowed && currenttemp && iob_data.lastTemp && currenttemp.rate !== iob_data.lastTemp.rate && lastTempAge > 10 && currenttemp.duration ) { @@ -822,39 +713,36 @@ 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+" ;"); - minIOBPredBG = Math.max(39,minIOBPredBG); - minCOBPredBG = Math.max(39,minCOBPredBG); - minUAMPredBG = Math.max(39,minUAMPredBG); - minPredBG = round(minIOBPredBG); + minIOBPredBG = Math.max(39,minIOBPredBG); + minCOBPredBG = Math.max(39,minCOBPredBG); + minUAMPredBG = Math.max(39,minUAMPredBG); + minPredBG = round(minIOBPredBG); - var fSensBG = Math.min(minPredBG,bg); + var fSensBG = Math.min(minPredBG,bg); - 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 = ( 1800 / (Math.log((((fSensBG * 0.5) + (bg * 0.5))/ins_val)+1)*TDD)); - //var future_sens_old = ( 277700 / (TDD * ((bg * 0.5) + (eventualBG * 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;"; + 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 = ( 1800 / (Math.log((((fSensBG * 0.5) + (bg * 0.5))/insulinDivisor)+1)*TDD)); + //var future_sens_old = ( 277700 / (TDD * ((bg * 0.5) + (eventualBG * 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 || eventualBG > bg) { + var future_sens = ( 1800 / (Math.log((bg/insulinDivisor)+1)*TDD)); + //var future_sens_old = ( 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 if( glucose_status.delta > 0 && eventualBG > target_bg || eventualBG > bg ) { - var future_sens = ( 1800 / (Math.log((bg/ins_val)+1)*TDD)); - //var future_sens_old = ( 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 = ( 1800 / (Math.log((fSensBG/ins_val)+1)*TDD)); - //var future_sens_old = ( 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;"; - } - future_sens = round(future_sens,1); - - - + else { + var future_sens = ( 1800 / (Math.log((fSensBG/insulinDivisor)+1)*TDD)); + //var future_sens_old = ( 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;"; + } + future_sens = round(future_sens,1); var fractionCarbsLeft = meal_data.mealCOB/meal_data.carbs; @@ -1079,25 +967,22 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } } - - - // calculate 30m low-temp required to get projected BG up to target - // multiply by 2 to low-temp faster for increased hypo safety - - var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / future_sens); - insulinReq = round( insulinReq , 2); - // calculate naiveInsulinReq based on naive_eventualBG - var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens); - naiveInsulinReq = round( naiveInsulinReq , 2); - if (minDelta < 0 && minDelta > expectedDelta) { - // if we're barely falling, newinsulinReq should be barely negative - var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2); - //console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq); - insulinReq = newinsulinReq; - } - // rate required to deliver insulinReq less insulin over 30m: - var rate = basal + (2 * insulinReq); - rate = round_basal(rate, profile); + // calculate 30m low-temp required to get projected BG up to target + // multiply by 2 to low-temp faster for increased hypo safety + var insulinReq = 2 * Math.min(0, (eventualBG - target_bg) / future_sens); + insulinReq = round( insulinReq , 2); + // calculate naiveInsulinReq based on naive_eventualBG + var naiveInsulinReq = Math.min(0, (naive_eventualBG - target_bg) / sens); + naiveInsulinReq = round( naiveInsulinReq , 2); + if (minDelta < 0 && minDelta > expectedDelta) { + // if we're barely falling, newinsulinReq should be barely negative + var newinsulinReq = round(( insulinReq * (minDelta / expectedDelta) ), 2); + //console.error("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq); + insulinReq = newinsulinReq; + } + // rate required to deliver insulinReq less insulin over 30m: + var rate = basal + (2 * insulinReq); + rate = round_basal(rate, profile); // if required temp < existing temp basal var insulinScheduled = currenttemp.duration * (currenttemp.rate - basal) / 60; @@ -1185,14 +1070,14 @@ var determine_basal = function determine_basal(glucose_status, currenttemp, iob_ } } else { // otherwise, calculate 30m high-temp required to get projected BG down to target - // insulinReq is the additional insulin required to get minPredBG down to target_bg - //console.error(minPredBG,eventualBG); - insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / future_sens, 2); - // if that would put us over max_iob, then reduce accordingly - if (insulinReq > max_iob-iob_data.iob) { - rT.reason += "max_iob " + max_iob + ", "; - insulinReq = max_iob-iob_data.iob; - } + // insulinReq is the additional insulin required to get minPredBG down to target_bg + //console.error(minPredBG,eventualBG); + insulinReq = round( (Math.min(minPredBG,eventualBG) - target_bg) / future_sens, 2); + // if that would put us over max_iob, then reduce accordingly + if (insulinReq > max_iob-iob_data.iob) { + rT.reason += "max_iob " + max_iob + ", "; + insulinReq = max_iob-iob_data.iob; + } // rate required to deliver insulinReq more insulin over 30m: rate = basal + (2 * insulinReq); diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.kt b/app/src/main/java/info/nightscout/androidaps/MainApp.kt index bc201bf3c8..62468ebbd9 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.kt +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.kt @@ -80,7 +80,7 @@ class MainApp : DaggerApplication() { @Inject lateinit var uel: UserEntryLogger @Inject lateinit var alarmSoundServiceHelper: AlarmSoundServiceHelper @Inject lateinit var notificationStore: NotificationStore - @Inject lateinit var processLifecycleListener: ProcessLifecycleListener + @Inject lateinit var processLifecycleListener: Provider @Inject lateinit var profileSwitchPlugin: ThemeSwitcherPlugin @Inject lateinit var localAlertUtils: LocalAlertUtils @Inject lateinit var rh: Provider @@ -94,7 +94,6 @@ class MainApp : DaggerApplication() { RxDogTag.install() setRxErrorHandler() LocaleHelper.update(this) - ProcessLifecycleOwner.get().lifecycle.addObserver(processLifecycleListener) var gitRemote: String? = BuildConfig.REMOTE var commitHash: String? = BuildConfig.HEAD @@ -151,6 +150,7 @@ class MainApp : DaggerApplication() { localAlertUtils.preSnoozeAlarms() doMigrations() uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps) + ProcessLifecycleOwner.get().lifecycle.addObserver(processLifecycleListener.get()) // schedule widget update refreshWidget = Runnable { diff --git a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt index 20bed45c84..73547e31c2 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/HistoryBrowseActivity.kt @@ -12,7 +12,7 @@ import com.google.android.material.datepicker.MaterialDatePicker import com.jjoe64.graphview.GraphView import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R -import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.activities.fragments.HistoryBrowserData import info.nightscout.androidaps.databinding.ActivityHistorybrowseBinding import info.nightscout.androidaps.events.EventAutosensCalculationFinished import info.nightscout.androidaps.events.EventCustomCalculationFinished @@ -21,27 +21,18 @@ import info.nightscout.androidaps.events.EventScale 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.general.nsclient.data.NSDeviceStatus -import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.interfaces.BuildHelper 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.EventIobCalculationProgress -import info.nightscout.androidaps.receivers.DataWorker import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.T -import info.nightscout.androidaps.utils.Translator -import info.nightscout.androidaps.interfaces.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 import io.reactivex.rxjava3.kotlin.plusAssign import java.util.* @@ -50,23 +41,16 @@ import kotlin.math.min class HistoryBrowseActivity : NoSplashAppCompatActivity() { + @Inject lateinit var historyBrowserData: HistoryBrowserData @Inject lateinit var injector: HasAndroidInjector @Inject lateinit var aapsSchedulers: AapsSchedulers - @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 repository: AppRepository @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var overviewMenus: OverviewMenus @Inject lateinit var dateUtil: DateUtil - @Inject lateinit var config: Config - @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() @@ -78,9 +62,6 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { private var rangeToDisplay = 24 // for graph // private var start: Long = 0 - private lateinit var iobCobCalculator: IobCobCalculatorPlugin - private lateinit var overviewData: OverviewData - private lateinit var binding: ActivityHistorybrowseBinding private var destroyed = false @@ -89,42 +70,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { binding = ActivityHistorybrowseBinding.inflate(layoutInflater) 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, - fabricPrivacy - ) - iobCobCalculator = - IobCobCalculatorPlugin( - injector, - aapsLogger, - aapsSchedulers, - rxBus, - sp, - rh, - profileFunction, - activePlugin, - fabricPrivacy, - dateUtil, - repository, - overviewData, - calculationWorkflow - ) - binding.left.setOnClickListener { - adjustTimeRange(overviewData.fromTime - T.hours(rangeToDisplay.toLong()).msecs()) + adjustTimeRange(historyBrowserData.overviewData.fromTime - T.hours(rangeToDisplay.toLong()).msecs()) loadAll("onClickLeft") } binding.right.setOnClickListener { - adjustTimeRange(overviewData.fromTime + T.hours(rangeToDisplay.toLong()).msecs()) + adjustTimeRange(historyBrowserData.overviewData.fromTime + T.hours(rangeToDisplay.toLong()).msecs()) loadAll("onClickRight") } binding.end.setOnClickListener { @@ -138,7 +89,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { } binding.zoom.setOnLongClickListener { Calendar.getInstance().also { calendar -> - calendar.timeInMillis = overviewData.fromTime + calendar.timeInMillis = historyBrowserData.overviewData.fromTime calendar[Calendar.MILLISECOND] = 0 calendar[Calendar.SECOND] = 0 calendar[Calendar.MINUTE] = 0 @@ -151,13 +102,13 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { binding.date.setOnClickListener { MaterialDatePicker.Builder.datePicker() - .setSelection(dateUtil.timeStampToUtcDateMillis(overviewData.fromTime)) + .setSelection(dateUtil.timeStampToUtcDateMillis(historyBrowserData.overviewData.fromTime)) .setTheme(R.style.DatePicker) .build() .apply { addOnPositiveButtonClickListener { selection -> - setTime(dateUtil.mergeUtcDateToTimestamp(overviewData.fromTime, selection)) - binding.date.text = dateUtil.dateAndTimeString(overviewData.fromTime) + setTime(dateUtil.mergeUtcDateToTimestamp(historyBrowserData.overviewData.fromTime, selection)) + binding.date.text = dateUtil.dateAndTimeString(historyBrowserData.overviewData.fromTime) loadAll("onClickDate") } } @@ -180,8 +131,8 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { prepareGraphsIfNeeded(overviewMenus.setting.size) savedInstanceState?.let { bundle -> rangeToDisplay = bundle.getInt("rangeToDisplay", 0) - overviewData.fromTime = bundle.getLong("start", 0) - overviewData.toTime = bundle.getLong("end", 0) + historyBrowserData.overviewData.fromTime = bundle.getLong("start", 0) + historyBrowserData.overviewData.toTime = bundle.getLong("end", 0) } } @@ -220,11 +171,11 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { .observeOn(aapsSchedulers.main) .subscribe({ rangeToDisplay = it.hours - setTime(overviewData.fromTime) + setTime(historyBrowserData.overviewData.fromTime) loadAll("rangeChange") }, fabricPrivacy::logException) - - if (overviewData.fromTime == 0L) { + updateCalcProgress(100) + if (historyBrowserData.overviewData.fromTime == 0L) { // set start of current day setTime(dateUtil.now()) loadAll("onResume") @@ -236,8 +187,8 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putInt("rangeToDisplay", rangeToDisplay) - outState.putLong("start", overviewData.fromTime) - outState.putLong("end", overviewData.toTime) + outState.putLong("start", historyBrowserData.overviewData.fromTime) + outState.putLong("end", historyBrowserData.overviewData.toTime) } private fun prepareGraphsIfNeeded(numOfGraphs: Int) { @@ -293,18 +244,18 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { } private fun adjustTimeRange(start: Long) { - overviewData.fromTime = start - overviewData.toTime = overviewData.fromTime + T.hours(rangeToDisplay.toLong()).msecs() - overviewData.endTime = overviewData.toTime + historyBrowserData.overviewData.fromTime = start + historyBrowserData.overviewData.toTime = historyBrowserData.overviewData.fromTime + T.hours(rangeToDisplay.toLong()).msecs() + historyBrowserData.overviewData.endTime = historyBrowserData.overviewData.toTime } private fun runCalculation(from: String) { calculationWorkflow.runCalculation( CalculationWorkflow.HISTORY_CALCULATION, - iobCobCalculator, - overviewData, + historyBrowserData.iobCobCalculator, + historyBrowserData.overviewData, from, - overviewData.toTime, + historyBrowserData.overviewData.toTime, bgDataReload = true, limitDataToOldestAvailable = false, cause = EventCustomCalculationFinished(), @@ -325,7 +276,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { } private fun updateDate() { - binding.date.text = dateUtil.dateAndTimeString(overviewData.fromTime) + binding.date.text = dateUtil.dateAndTimeString(historyBrowserData.overviewData.fromTime) binding.zoom.text = rangeToDisplay.toString() } @@ -337,9 +288,9 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { updateDate() val pump = activePlugin.activePump - val graphData = GraphData(injector, binding.bgGraph, overviewData) + val graphData = GraphData(injector, binding.bgGraph, historyBrowserData.overviewData) val menuChartSettings = overviewMenus.setting - graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine()) + graphData.addInRangeArea(historyBrowserData.overviewData.fromTime, historyBrowserData.overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine()) graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal], context) if (buildHelper.isDev()) graphData.addBucketedData() graphData.addTreatments(context) @@ -355,7 +306,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { // set manual x bounds to have nice steps graphData.setNumVerticalLabels() - graphData.formatAxis(overviewData.fromTime, overviewData.endTime) + graphData.formatAxis(historyBrowserData.overviewData.fromTime, historyBrowserData.overviewData.endTime) graphData.performUpdate() @@ -365,7 +316,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { val now = System.currentTimeMillis() for (g in 0 until min(secondaryGraphs.size, menuChartSettings.size + 1)) { - val secondGraphData = GraphData(injector, secondaryGraphs[g], overviewData) + val secondGraphData = GraphData(injector, secondaryGraphs[g], historyBrowserData.overviewData) var useABSForScale = false var useIobForScale = false var useCobForScale = false @@ -393,7 +344,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() { if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(useDSForScale, 1.0) // set manual x bounds to have nice steps - secondGraphData.formatAxis(overviewData.fromTime, overviewData.endTime) + secondGraphData.formatAxis(historyBrowserData.overviewData.fromTime, historyBrowserData.overviewData.endTime) secondGraphData.addNowLine(now) secondaryGraphsData.add(secondGraphData) } diff --git a/app/src/main/java/info/nightscout/androidaps/activities/fragments/HistoryBrowserData.kt b/app/src/main/java/info/nightscout/androidaps/activities/fragments/HistoryBrowserData.kt new file mode 100644 index 0000000000..2fba78b07c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/activities/fragments/HistoryBrowserData.kt @@ -0,0 +1,72 @@ +package info.nightscout.androidaps.activities.fragments + +import dagger.android.HasAndroidInjector +import info.nightscout.androidaps.database.AppRepository +import info.nightscout.androidaps.interfaces.ActivePlugin +import info.nightscout.androidaps.interfaces.ProfileFunction +import info.nightscout.androidaps.interfaces.ResourceHelper +import info.nightscout.androidaps.plugins.bus.RxBus +import info.nightscout.androidaps.plugins.general.overview.OverviewData +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.utils.DateUtil +import info.nightscout.androidaps.utils.DefaultValueHelper +import info.nightscout.androidaps.utils.FabricPrivacy +import info.nightscout.androidaps.utils.rx.AapsSchedulers +import info.nightscout.androidaps.workflow.CalculationWorkflow +import info.nightscout.shared.logging.AAPSLogger +import info.nightscout.shared.sharedPreferences.SP +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class HistoryBrowserData @Inject constructor( + injector: HasAndroidInjector, + aapsSchedulers: AapsSchedulers, + rxBus: RxBus, + aapsLogger: AAPSLogger, + rh: ResourceHelper, + dateUtil: DateUtil, + sp: SP, + activePlugin: ActivePlugin, + defaultValueHelper: DefaultValueHelper, + profileFunction: ProfileFunction, + repository: AppRepository, + fabricPrivacy: FabricPrivacy, + calculationWorkflow: CalculationWorkflow +) { + + var iobCobCalculator: IobCobCalculatorPlugin + var overviewData: OverviewData + + init { + // 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, + fabricPrivacy + ) + iobCobCalculator = + IobCobCalculatorPlugin( + injector, + aapsLogger, + aapsSchedulers, + rxBus, + sp, + rh, + profileFunction, + activePlugin, + fabricPrivacy, + dateUtil, + repository, + overviewData, + calculationWorkflow + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMBDynamicISF/DetermineBasalAdapterSMBDynamicISFJS.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMBDynamicISF/DetermineBasalAdapterSMBDynamicISFJS.kt index d5a33606eb..234735a214 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMBDynamicISF/DetermineBasalAdapterSMBDynamicISFJS.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMBDynamicISF/DetermineBasalAdapterSMBDynamicISFJS.kt @@ -22,6 +22,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.interfaces.ResourceHelper +import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.shared.SafeParse import info.nightscout.shared.logging.AAPSLogger @@ -36,6 +37,7 @@ import java.io.IOException import java.lang.reflect.InvocationTargetException import java.nio.charset.StandardCharsets import javax.inject.Inject +import kotlin.math.ln class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scriptReader: ScriptReader, private val injector: HasAndroidInjector) : DetermineBasalAdapterInterface { @@ -194,10 +196,6 @@ 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)) this.profile.put("lgsThreshold", Profile.toMgdl(sp.getDouble(R.string.key_lgs_threshold, 65.0))) - val insulin = activePlugin.activeInsulin - val insulinType = insulin.friendlyName - val insulinPeak = insulin.peak - //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", 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)); @@ -227,9 +225,6 @@ 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("insulinType", insulinType) - this.profile.put("insulinPeak", insulinPeak) 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) @@ -237,8 +232,7 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri 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)) + this.profile.put("autosens_min", SafeParse.stringToDouble(sp.getString(R.string.key_openapsama_autosens_min, "0.7"))) //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") @@ -270,19 +264,53 @@ class DetermineBasalAdapterSMBDynamicISFJS internal constructor(private val scri this.mealData.put("lastBolusTime", mealData.lastBolusTime) this.mealData.put("lastCarbTime", mealData.lastCarbTime) - this.mealData.put("TDDAIMI1", tddCalculator.averageTDD(tddCalculator.calculate(1))?.totalAmount) - this.mealData.put("TDDAIMI7", tddCalculator.averageTDD(tddCalculator.calculate(7))?.totalAmount) - this.mealData.put("TDDLast4", tddCalculator.calculateDaily(-4, 0).totalAmount) - this.mealData.put("TDD4to8", tddCalculator.calculateDaily(-8, -4).totalAmount) - this.mealData.put("TDD24", tddCalculator.calculateDaily(-24, 0).totalAmount) + val tdd1D = tddCalculator.averageTDD(tddCalculator.calculate(1))?.totalAmount + val tdd7D = tddCalculator.averageTDD(tddCalculator.calculate(7))?.totalAmount + val tddLast24H = tddCalculator.calculateDaily(-24, 0).totalAmount + val tddLast4H = tddCalculator.calculateDaily(-4, 0).totalAmount + val tddLast8to4H = tddCalculator.calculateDaily(-8, -4).totalAmount + val tddWeightedFromLast8H = ((1.4 * tddLast4H) + (0.6 * tddLast8to4H)) * 3 +// console.error("Rolling 8 hours weight average: " + tdd_last8_wt + "; "); +// console.error("1-day average TDD is: " + tdd1 + "; "); +// console.error("7-day average TDD is: " + tdd7 + "; "); + var tdd = + if (tdd1D != null && tdd7D != null) (tddWeightedFromLast8H * 0.33) + (tdd7D * 0.34) + (tdd1D * 0.33) + else tddWeightedFromLast8H +// console.log("TDD = " + TDD + " using average of 7-day, 1-day and weighted 8hr average"); - if (constraintChecker.isAutosensModeEnabled().value()) { - autosensData.put("ratio", autosensDataRatio) - } else { - autosensData.put("ratio", 1.0) +// console.log("Insulin Peak = " + insulin.peak + "; "); + + val insulin = activePlugin.activeInsulin + val insulinDivisor = when { + insulin.peak > 65 -> 55 // lyumjev peak: 45 + insulin.peak > 50 -> 65 // ultra rapid peak: 55 + else -> 75 // rapid peak: 75 } +// console.log("For " + insulin.friendlyName + " (insulin peak: " + insulin.peak + ") insulin divisor is: " + ins_val + "; "); + + val dynISFadjust = SafeParse.stringToDouble(sp.getString(R.string.key_DynISFAdjust, "100")) / 100.0 + tdd *= dynISFadjust + + var variableSensitivity = 1800 / (tdd * (ln((glucoseStatus.glucose / insulinDivisor) + 1))) + variableSensitivity = Round.roundTo(variableSensitivity, 0.1) + + if (dynISFadjust != 1.0) { +// console.log("TDD adjusted to " + TDD + " using adjustment factor of " + dynISFadjust + "; "); + } +// console.log("Current sensitivity for predictions is " + variable_sens + " based on current bg"); + + this.profile.put("variable_sens", variableSensitivity) + this.profile.put("insulinDivisor", insulinDivisor) + this.profile.put("TDD", tdd) + + + if (sp.getBoolean(R.string.key_adjust_sensitivity, false) && tdd7D != null) + autosensData.put("ratio", tddLast24H / tdd7D) + else + autosensData.put("ratio", 1.0) + this.microBolusAllowed = microBolusAllowed smbAlwaysAllowed = advancedFiltering currentTime = now diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt index 92002eab4d..ff3fc89a4a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt @@ -312,7 +312,7 @@ class ActionsFragment : DaggerFragment() { for (customAction in customActions) { if (!customAction.isEnabled) continue - val btn = SingleClickButton(currentContext, null, android.R.attr.buttonStyle) + val btn = SingleClickButton(currentContext, null, R.attr.customBtnStyle) btn.text = rh.gs(customAction.name) val layoutParams = LinearLayout.LayoutParams( diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneFragment.kt index 0f2834c90e..6ad3b9e04e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneFragment.kt @@ -115,6 +115,7 @@ class AutotuneFragment : DaggerFragment() { } autotunePlugin.selectedProfile = profileName resetParam() + binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble() } updateGui() } @@ -275,6 +276,7 @@ class AutotuneFragment : DaggerFragment() { .observeOn(aapsSchedulers.main) .subscribe({ updateGui() }, fabricPrivacy::logException) checkNewDay() + binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble() updateGui() } @@ -287,7 +289,6 @@ class AutotuneFragment : DaggerFragment() { @Synchronized private fun updateGui() { _binding ?: return - binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble() profileStore = activePlugin.activeProfileSource.profile ?: ProfileStore(injector, JSONObject(), dateUtil) profileName = if (binding.profileList.text.toString() == rh.gs(R.string.active)) "" else binding.profileList.text.toString() profileFunction.getProfile()?.let { currentProfile -> @@ -387,7 +388,7 @@ class AutotuneFragment : DaggerFragment() { try { if (autotunePlugin.calculationRunning) binding.tuneDays.value = autotunePlugin.lastNbDays.toDouble() - if (binding.tuneDays.value != autotunePlugin.lastNbDays.toDouble()) { + if (binding.tuneDays.text != autotunePlugin.lastNbDays) { autotunePlugin.lastNbDays = binding.tuneDays.text resetParam(false) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneIob.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneIob.kt index a634ee876c..6b29491848 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneIob.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/autotune/AutotuneIob.kt @@ -381,9 +381,11 @@ open class AutotuneIob @Inject constructor( } } TherapyEvent.Type.COMBO_BOLUS -> - extendedBolus?.let { - val profile = profileFunction.getProfile(it.timestamp) - it.toJson(true, profile!!, dateUtil) + extendedBolus?.let { ebr -> + val profile = profileFunction.getProfile(ebr.timestamp) + profile?.let { + ebr.toJson(true, it, dateUtil) + } } TherapyEvent.Type.CORRECTION_BOLUS -> bolusTreatment?.toJson(true, dateUtil) TherapyEvent.Type.CARBS_CORRECTION -> carbsTreatment?.toJson(true, dateUtil) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index 8ecba9d5ad..54a2bbcb40 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -120,7 +120,6 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList @Inject lateinit var repository: AppRepository @Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider @Inject lateinit var overviewData: OverviewData - @Inject lateinit var overviewPlugin: OverviewPlugin @Inject lateinit var automationPlugin: AutomationPlugin @Inject lateinit var bgQualityCheckPlugin: BgQualityCheckPlugin @@ -417,7 +416,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview) (context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?)?.cancel(Constants.notificationID) rxBus.send(EventMobileToWear(EventData.CancelNotification(dateUtil.now()))) - Thread { loop.acceptChangeRequest() }.run() + Thread { loop.acceptChangeRequest() }.start() binding.buttonsLayout.acceptTempButton.visibility = View.GONE }) }) @@ -582,7 +581,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList for (event in events) if (event.isEnabled && event.trigger.shouldRun()) context?.let { context -> - SingleClickButton(context).also { + SingleClickButton(context, null, R.attr.customBtnStyle).also { 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 -> @@ -827,7 +826,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } } - fun updateProfile() { + private fun updateProfile() { val profile = profileFunction.getProfile() runOnUiThread { _binding ?: return@runOnUiThread @@ -885,7 +884,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } } - fun updateTime() { + private fun updateTime() { _binding ?: return binding.infoLayout.time.text = dateUtil.timeString(dateUtil.now()) // Status lights @@ -915,7 +914,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList ) } - fun updateIobCob() { + private fun updateIobCob() { val iobText = overviewData.iobText(iobCobCalculator) val iobDialogText = overviewData.iobDialogText(iobCobCalculator) val displayText = overviewData.cobInfo(iobCobCalculator).displayText(rh, dateUtil, buildHelper.isEngineeringMode()) @@ -999,6 +998,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList val pump = activePlugin.activePump val graphData = GraphData(injector, binding.graphsLayout.bgGraph, overviewData) val menuChartSettings = overviewMenus.setting + if (menuChartSettings.isEmpty()) return graphData.addInRangeArea(overviewData.fromTime, overviewData.endTime, defaultValueHelper.determineLowLine(), defaultValueHelper.determineHighLine()) graphData.addBgReadings(menuChartSettings[0][OverviewMenus.CharType.PRE.ordinal], context) if (buildHelper.isDev()) graphData.addBucketedData() @@ -1084,7 +1084,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList private fun updateSensitivity() { _binding ?: return - if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) { + if (constraintChecker.isAutosensModeEnabled().value()) { binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_swap_vert_black_48dp_green) } else { binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_x_swap_vert) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt index baa764d2bd..2431dc5f61 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt @@ -69,14 +69,16 @@ class OverviewMenus @Inject constructor( private var _setting: MutableList> = ArrayList() val setting: List> - get() = _setting.toMutableList() // implicitly does a list copy + @Synchronized get() = _setting.toMutableList() // implicitly does a list copy + @Synchronized private fun storeGraphConfig() { val sts = Gson().toJson(_setting) sp.putString(R.string.key_graphconfig, sts) aapsLogger.debug(sts) } + @Synchronized fun loadGraphConfig() { val sts = sp.getString(R.string.key_graphconfig, "") if (sts.isNotEmpty()) { @@ -115,7 +117,7 @@ class OverviewMenus @Inject constructor( val used = arrayListOf() for (g in 0 until numOfGraphs) { - if (g != 0 && g < numOfGraphs) { + if (g != 0) { val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- ${rh.gs(R.string.graph_menu_divider_header)} $g -------") dividerItem.isCheckable = true dividerItem.isChecked = true @@ -150,36 +152,38 @@ class OverviewMenus @Inject constructor( } popup.setOnMenuItemClickListener { - try { - // id < 100 graph header - divider 1, 2, 3 ..... - when { - it.itemId == SCALE_ID -> { - // do nothing, submenu - } + synchronized(this) { + try { + // id < 100 graph header - divider 1, 2, 3 ..... + when { + it.itemId == SCALE_ID -> { + // do nothing, submenu + } - it.itemId > SCALE_ID && it.itemId < SCALE_ID + 100 -> { - val hours = it.itemId - SCALE_ID // 6,12,.... - rxBus.send(EventScale(hours)) - } + it.itemId > SCALE_ID && it.itemId < SCALE_ID + 100 -> { + val hours = it.itemId - SCALE_ID // 6,12,.... + rxBus.send(EventScale(hours)) + } - it.itemId == numOfGraphs -> { - // add new empty - _setting.add(Array(CharType.values().size) { false }) - } + it.itemId == numOfGraphs -> { + // add new empty + _setting.add(Array(CharType.values().size) { false }) + } - it.itemId < 100 -> { - // remove graph - _setting.removeAt(it.itemId) - } + it.itemId < 100 -> { + // remove graph + _setting.removeAt(it.itemId) + } - else -> { - val graphNumber = it.itemId / 100 - 1 - val item = it.itemId % 100 - _setting[graphNumber][item] = !it.isChecked + else -> { + val graphNumber = it.itemId / 100 - 1 + val item = it.itemId % 100 + _setting[graphNumber][item] = !it.isChecked + } } + } catch (exception: Exception) { + fabricPrivacy.logException(exception) } - } catch (exception: Exception) { - fabricPrivacy.logException(exception) } storeGraphConfig() setupChartMenu(context, chartButton) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt index 61f0558009..e705b0b8bb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt @@ -1,7 +1,6 @@ package info.nightscout.androidaps.plugins.general.wear import android.content.Context -import android.content.Intent import dagger.android.HasAndroidInjector import info.nightscout.androidaps.R import info.nightscout.androidaps.events.EventAutosensCalculationFinished @@ -10,14 +9,14 @@ import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType +import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataHandlerMobile -import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile +import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobileHelper import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.sharedPreferences.SP @@ -37,7 +36,8 @@ class WearPlugin @Inject constructor( private val fabricPrivacy: FabricPrivacy, private val rxBus: RxBus, private val context: Context, - private val dataHandlerMobile: DataHandlerMobile + private val dataHandlerMobile: DataHandlerMobile, + val dataLayerListenerServiceMobileHelper: DataLayerListenerServiceMobileHelper ) : PluginBase( PluginDescription() @@ -57,7 +57,7 @@ class WearPlugin @Inject constructor( override fun onStart() { super.onStart() - context.startService(Intent(context, DataLayerListenerServiceMobile::class.java)) + dataLayerListenerServiceMobileHelper.startService(context) disposable += rxBus .toObservable(EventDismissBolusProgressIfRunning::class.java) .observeOn(aapsSchedulers.io) @@ -94,6 +94,6 @@ class WearPlugin @Inject constructor( override fun onStop() { disposable.clear() super.onStop() - context.stopService(Intent(context, DataLayerListenerServiceMobile::class.java)) + dataLayerListenerServiceMobileHelper.stopService(context) } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt index 4292307c59..1a3cd7f601 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobile.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.plugins.general.wear.wearintegration +import android.os.Binder import android.os.Handler import android.os.HandlerThread import com.google.android.gms.tasks.Tasks @@ -10,14 +11,12 @@ import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.events.EventMobileToWear import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.plugins.bus.RxBus -import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus import info.nightscout.androidaps.plugins.general.wear.WearPlugin import info.nightscout.androidaps.plugins.general.wear.events.EventWearUpdateGui import info.nightscout.androidaps.receivers.ReceiverStatusStore import info.nightscout.androidaps.utils.DefaultValueHelper import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.rx.AapsSchedulers -import info.nightscout.androidaps.utils.wizard.QuickWizard import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.LTag import info.nightscout.shared.sharedPreferences.SP @@ -38,9 +37,7 @@ class DataLayerListenerServiceMobile : WearableListenerService() { @Inject lateinit var loop: Loop @Inject lateinit var wearPlugin: WearPlugin @Inject lateinit var sp: SP - @Inject lateinit var quickWizard: QuickWizard @Inject lateinit var config: Config - @Inject lateinit var nsDeviceStatus: NSDeviceStatus @Inject lateinit var receiverStatusStore: ReceiverStatusStore @Inject lateinit var repository: AppRepository @Inject lateinit var defaultValueHelper: DefaultValueHelper @@ -48,6 +45,11 @@ class DataLayerListenerServiceMobile : WearableListenerService() { @Inject lateinit var rxBus: RxBus @Inject lateinit var aapsSchedulers: AapsSchedulers + inner class LocalBinder : Binder() { + + fun getService(): DataLayerListenerServiceMobile = this@DataLayerListenerServiceMobile + } + private val dataClient by lazy { Wearable.getDataClient(this) } private val messageClient by lazy { Wearable.getMessageClient(this) } private val capabilityClient by lazy { Wearable.getCapabilityClient(this) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobileHelper.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobileHelper.kt new file mode 100644 index 0000000000..941e04eb53 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration/DataLayerListenerServiceMobileHelper.kt @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.plugins.general.wear.wearintegration + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import info.nightscout.androidaps.interfaces.NotificationHolder +import javax.inject.Inject +import javax.inject.Singleton + +/* + This code replaces following + val alarm = Intent(context, DataLayerListenerServiceMobile::class.java) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(alarm) else context.startService(alarm) + + it fails randomly with error + Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{e317f7e u0 info.nightscout.nsclient/info.nightscout.androidaps.services.DataLayerListenerServiceMobile} + + */ +@Singleton +class DataLayerListenerServiceMobileHelper @Inject constructor( + private val notificationHolder: NotificationHolder +) { + + fun startService(context: Context) { + val connection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + // The binder of the service that returns the instance that is created. + val binder: DataLayerListenerServiceMobile.LocalBinder = service as DataLayerListenerServiceMobile.LocalBinder + + val dataLayerListenerServiceMobile: DataLayerListenerServiceMobile = binder.getService() + + context.startForegroundService(Intent(context, DataLayerListenerServiceMobile::class.java)) + + // This is the key: Without waiting Android Framework to call this method + // inside Service.onCreate(), immediately call here to post the notification. + dataLayerListenerServiceMobile.startForeground(notificationHolder.notificationID, notificationHolder.notification) + + // Release the connection to prevent leaks. + context.unbindService(this) + } + + override fun onServiceDisconnected(name: ComponentName?) { + } + } + + try { + context.bindService(Intent(context, DataLayerListenerServiceMobile::class.java), connection, Context.BIND_AUTO_CREATE) + } catch (ignored: RuntimeException) { + // This is probably a broadcast receiver context even though we are calling getApplicationContext(). + // Just call startForegroundService instead since we cannot bind a service to a + // broadcast receiver context. The service also have to call startForeground in + // this case. + context.startForegroundService(Intent(context, DataLayerListenerServiceMobile::class.java)) + } + } + + fun stopService(context: Context) { + context.stopService(Intent(context, DataLayerListenerServiceMobile::class.java)) + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt index 4d157a874a..12f240b1e3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/IobCobOref1Worker.kt @@ -97,11 +97,11 @@ class IobCobOref1Worker( 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): ${data.from}") + aapsLogger.debug(LTag.AUTOSENS, {"Aborting calculation thread (No bucketed data available): ${data.from}"}) return Result.success(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)) + 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) { @@ -156,15 +156,15 @@ class IobCobOref1Worker( val hourAgoData = ads.getAutosensDataAtTime(hourAgo) if (hourAgoData != null) { val initialIndex = autosensDataTable.indexOfKey(hourAgoData.time) - aapsLogger.debug(LTag.AUTOSENS, ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()) + aapsLogger.debug(LTag.AUTOSENS, { ">>>>> bucketed_data.size()=" + bucketedData.size + " i=" + i + " hourAgoData=" + hourAgoData.toString()}) var past = 1 try { while (past < 12) { val ad = autosensDataTable.valueAt(initialIndex + past) - aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + ad?.toString()) + aapsLogger.debug(LTag.AUTOSENS, {">>>>> past=" + past + " ad=" + ad?.toString()}) if (ad == null) { - aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString()) - aapsLogger.debug(LTag.AUTOSENS, bucketedData.toString()) + aapsLogger.debug(LTag.AUTOSENS, {autosensDataTable.toString()}) + aapsLogger.debug(LTag.AUTOSENS, {bucketedData.toString()}) //aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadingsDataTable().toString()) val notification = Notification(Notification.SEND_LOGFILES, rh.gs(R.string.sendlogfiles), Notification.LOW) rxBus.send(EventNewNotification(notification)) @@ -319,14 +319,12 @@ class IobCobOref1Worker( 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 - ) + {"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()) + aapsLogger.debug(LTag.AUTOSENS, {autosensData.toString()}) } data.iobCobCalculator.ads = ads Thread { @@ -335,7 +333,7 @@ class IobCobOref1Worker( }.start() } finally { rxBus.send(EventIobCalculationProgress(CalculationWorkflow.ProgressData.IOB_COB_OREF, 100, data.cause)) - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA thread ended: ${data.from}") + aapsLogger.debug(LTag.AUTOSENS, {"AUTOSENSDATA thread ended: ${data.from}"}) profiler.log(LTag.AUTOSENS, "IobCobOref1Thread", start) } return Result.success() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlunovoPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlunovoPlugin.kt index 239a317781..6a02daa322 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/source/GlunovoPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/source/GlunovoPlugin.kt @@ -89,80 +89,84 @@ class GlunovoPlugin @Inject constructor( private fun handleNewData() { if (!isEnabled()) return - context.contentResolver.query(contentUri, null, null, null, null)?.let { cr -> - val glucoseValues = mutableListOf() - val calibrations = mutableListOf() - cr.moveToFirst() + try { + context.contentResolver.query(contentUri, null, null, null, null)?.let { cr -> + val glucoseValues = mutableListOf() + val calibrations = mutableListOf() + cr.moveToFirst() - while (!cr.isAfterLast) { - val timestamp = cr.getLong(0) - val value = cr.getDouble(1) //value in mmol/l... - val curr = cr.getDouble(2) + while (!cr.isAfterLast) { + val timestamp = cr.getLong(0) + val value = cr.getDouble(1) //value in mmol/l... + val curr = cr.getDouble(2) - // bypass already processed - if (timestamp < sp.getLong(R.string.key_last_processed_glunovo_timestamp, 0L)) { - cr.moveToNext() - continue - } + // bypass already processed + if (timestamp < sp.getLong(R.string.key_last_processed_glunovo_timestamp, 0L)) { + cr.moveToNext() + continue + } - if (timestamp > dateUtil.now() || timestamp == 0L) { - aapsLogger.error(LTag.BGSOURCE, "Error in received data date/time $timestamp") - cr.moveToNext() - continue - } + if (timestamp > dateUtil.now() || timestamp == 0L) { + aapsLogger.error(LTag.BGSOURCE, "Error in received data date/time $timestamp") + cr.moveToNext() + continue + } - if (value < 2 || value > 25) { - aapsLogger.error(LTag.BGSOURCE, "Error in received data value (value out of bounds) $value") - cr.moveToNext() - continue - } + if (value < 2 || value > 25) { + aapsLogger.error(LTag.BGSOURCE, "Error in received data value (value out of bounds) $value") + cr.moveToNext() + continue + } - if (curr != 0.0) - glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( - timestamp = timestamp, - value = value * Constants.MMOLL_TO_MGDL, - raw = 0.0, - noise = null, - trendArrow = GlucoseValue.TrendArrow.NONE, - sourceSensor = GlucoseValue.SourceSensor.GLUNOVO_NATIVE - ) - else - calibrations.add( - CgmSourceTransaction.Calibration( + if (curr != 0.0) + glucoseValues += CgmSourceTransaction.TransactionGlucoseValue( timestamp = timestamp, - value = value, - glucoseUnit = TherapyEvent.GlucoseUnit.MMOL + value = value * Constants.MMOLL_TO_MGDL, + raw = 0.0, + noise = null, + trendArrow = GlucoseValue.TrendArrow.NONE, + sourceSensor = GlucoseValue.SourceSensor.GLUNOVO_NATIVE ) - ) - sp.putLong(R.string.key_last_processed_glunovo_timestamp, timestamp) - cr.moveToNext() - } - cr.close() + else + calibrations.add( + CgmSourceTransaction.Calibration( + timestamp = timestamp, + value = value, + glucoseUnit = TherapyEvent.GlucoseUnit.MMOL + ) + ) + sp.putLong(R.string.key_last_processed_glunovo_timestamp, timestamp) + cr.moveToNext() + } + cr.close() - if (glucoseValues.isNotEmpty() || calibrations.isNotEmpty()) - repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, null)) - .doOnError { - aapsLogger.error(LTag.DATABASE, "Error while saving values from Glunovo App", it) - } - .blockingGet() - .also { savedValues -> - savedValues.inserted.forEach { - xDripBroadcast.send(it) - aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") + if (glucoseValues.isNotEmpty() || calibrations.isNotEmpty()) + repository.runTransactionForResult(CgmSourceTransaction(glucoseValues, calibrations, null)) + .doOnError { + aapsLogger.error(LTag.DATABASE, "Error while saving values from Glunovo App", it) } - savedValues.calibrationsInserted.forEach { calibration -> - calibration.glucose?.let { glucosevalue -> - uel.log( - UserEntry.Action.CALIBRATION, - UserEntry.Sources.Dexcom, - ValueWithUnit.Timestamp(calibration.timestamp), - ValueWithUnit.TherapyEventType(calibration.type), - ValueWithUnit.fromGlucoseUnit(glucosevalue, calibration.glucoseUnit.toString) - ) + .blockingGet() + .also { savedValues -> + savedValues.inserted.forEach { + xDripBroadcast.send(it) + aapsLogger.debug(LTag.DATABASE, "Inserted bg $it") + } + savedValues.calibrationsInserted.forEach { calibration -> + calibration.glucose?.let { glucosevalue -> + uel.log( + UserEntry.Action.CALIBRATION, + UserEntry.Sources.Dexcom, + ValueWithUnit.Timestamp(calibration.timestamp), + ValueWithUnit.TherapyEventType(calibration.type), + ValueWithUnit.fromGlucoseUnit(glucosevalue, calibration.glucoseUnit.toString) + ) + } + aapsLogger.debug(LTag.DATABASE, "Inserted calibration $calibration") } - aapsLogger.debug(LTag.DATABASE, "Inserted calibration $calibration") } - } + } + } catch (e: SecurityException) { + aapsLogger.error(LTag.CORE, "Exception", e) } } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt b/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt index 2be9e2eef9..cea1f8bb35 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/AndroidPermission.kt @@ -50,12 +50,20 @@ class AndroidPermission @Inject constructor( } if (test) { if (activity is DaggerAppCompatActivityWithResult) - activity.requestMultiplePermissions.launch(permissions) + try { + activity.requestMultiplePermissions.launch(permissions) + } catch (ignored: IllegalStateException) { + ToastUtils.errorToast(activity, rh.gs(R.string.error_asking_for_permissions)) + } } if (testBattery) { try { if (activity is DaggerAppCompatActivityWithResult) - activity.callForBatteryOptimization.launch(null) + try { + activity.callForBatteryOptimization.launch(null) + } catch (ignored: IllegalStateException) { + ToastUtils.errorToast(activity, rh.gs(R.string.error_asking_for_permissions)) + } } catch (e: ActivityNotFoundException) { permissionBatteryOptimizationFailed = true OKDialog.show(activity, rh.gs(R.string.permission), rh.gs(R.string.alert_dialog_permission_battery_optimization_failed)) { activity.recreate() } @@ -145,8 +153,10 @@ class AndroidPermission @Inject constructor( if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { // Show alert dialog to the user saying a separate permission is needed // Launch the settings activity if the user prefers - val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, - Uri.parse("package:" + activity.packageName)) + val intent = Intent( + Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:" + activity.packageName) + ) activity.startActivity(intent) } } diff --git a/app/src/main/java/info/nightscout/androidaps/widget/Widget.kt b/app/src/main/java/info/nightscout/androidaps/widget/Widget.kt index b4a2cbcd29..3d8c1e62cd 100644 --- a/app/src/main/java/info/nightscout/androidaps/widget/Widget.kt +++ b/app/src/main/java/info/nightscout/androidaps/widget/Widget.kt @@ -204,7 +204,7 @@ class Widget : AppWidgetProvider() { } } - fun updateProfile(views: RemoteViews) { + private fun updateProfile(views: RemoteViews) { val profileTextColor = profileFunction.getProfile()?.let { if (it is ProfileSealed.EPS) { @@ -226,7 +226,7 @@ class Widget : AppWidgetProvider() { } private fun updateSensitivity(views: RemoteViews) { - if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) + if (constraintChecker.isAutosensModeEnabled().value()) views.setImageViewResource(R.id.sensitivity_icon, R.drawable.ic_swap_vert_black_48dp_green) else views.setImageViewResource(R.id.sensitivity_icon, R.drawable.ic_x_swap_vert) @@ -256,7 +256,7 @@ class Widget : AppWidgetProvider() { internal fun updateWidget(context: Context) { context.sendBroadcast(Intent().also { - it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, AppWidgetManager.getInstance(context).getAppWidgetIds(ComponentName(context, Widget::class.java))) + it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, AppWidgetManager.getInstance(context)?.getAppWidgetIds(ComponentName(context, Widget::class.java))) it.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE }) } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_historybrowse.xml b/app/src/main/res/layout/activity_historybrowse.xml index c3d0eec40a..26673e7b76 100644 --- a/app/src/main/res/layout/activity_historybrowse.xml +++ b/app/src/main/res/layout/activity_historybrowse.xml @@ -1,5 +1,5 @@ - - - + android:layout_height="300dp"> - + diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 720897882e..ca89f7b857 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -1046,4 +1046,5 @@ Zablokováno možností nabíjení Zablokováno možností připojení (Žádné hodinky nejsou připojeny) + Chyba žádosti o oprávnění diff --git a/app/src/main/res/values-da-rDK/exam.xml b/app/src/main/res/values-da-rDK/exam.xml index 2a4276dfe3..75e3579ca8 100644 --- a/app/src/main/res/values-da-rDK/exam.xml +++ b/app/src/main/res/values-da-rDK/exam.xml @@ -123,6 +123,7 @@ Notering af kanyleskift vil nulstille Autosens ratio tilbage til 100%. Nogle af plugin mulighederne har konfigurerbare tidsintervaller, der kan indstilles af brugeren. https://androidaps.readthedocs.io/en/latest/EN/Configuration/Sensitivity-detection-and-COB.html + https://androidaps.readthedocs.io/en/latest/Usage/Open-APS-features.html?highlight=Autosens#autosens Kulhydrat indtastningsfejl Hvad gør du, hvis du har lavet en forkert kulhydrat indtastning? Slet den forkerte indtastning i Behandlinger og indtast korrekte nye kulhydrat værdier. @@ -135,6 +136,19 @@ Sammenlign værdier i AndroidAPS og pumpehistorik (hvis pumpen understøtter dette). Bolus en del af din beregnede \"glemte\" insulin med enten sprøjter / pen eller brug af en kanylefyldning. Gør ingenting og tillad AndroidAPS at rette op på højt blodsukker. + Kulhydrater om bord (COB) + Hvordan ændring af ISF værdi påvirker COB beregning? + Ved øget ISF, vil kulhydrater være længere tid om at absorberes + Ved øget ISF, vil kulhydrater være kortere tid om at absorberes + Øget ISF vil ikke påvirke absorbering af beregnet kulhydrat + Hvordan ændring af IC værdi påvirker COB beregning? + Ved øget IC, vil kulhydrater være længere tid om at absorberes + Ved øget IC, vil kulhydrater være kortere tid om at absorberes + Øget IC vil ikke påvirke absorbering af beregnet kulhydrat + Hvordan skift af profil procent påvirker COB beregning? + Ved indstilling af profil til 150%, vil kulhydrater være længere tid om at absorberes + Ved indstilling af profil til 150%, vil kulhydrater være kortere tid om at absorberes + Ved indstilling af profil til 150%, påvirkes absorbering af beregnet kulhydrat ikke Insulin om bord (IOB) IOB-værdi påvirkes af midlertidige basaler. Høj midlertidlig basal vil ikke blive givet, når dit blodsukker er under målet. diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index c2c5332077..68e4976f86 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -6,6 +6,7 @@ Behandlings sikkerhed Maks tilladt bolus [IE] Maks tilladte kulhydrater [g] + BS under værdi for LGS grænse %1$s indstillinger Indstillinger Opdater behandlinger fra NS @@ -432,12 +433,15 @@ Aktiver lokale udsendelser. OpenAPS SMB Dynamisk ISF + DynamiskISF-justeringsfaktor % + Justeringsfaktor for DynamiskISF. Indstil mere end 100% for mere aggressive korrektionsdoser og mindre end 100% for mindre aggressive korrektioner. Aktiver UAM Aktiver SMB Brug Super Mikro Boluser i stedet for midlertidig basal for hurtigere handling Detektering af uanmeldte måltider IOB Kurve Peak-Tid Spidstidspunkt [min] + Top Free-Peak Oref Rapid-Acting Oref Ultra-Rapid Oref @@ -589,6 +593,7 @@ Denne værdi kaldes Max IOB i OpenAPS kontekst\nOpenAPS vil ikke tilføje mere insulin, hvis den aktuelle IOB er større end denne værdi Måltid max absorptionstid [h] Tid hvor ethvert måltid betragtes som absorberet. Resterende kulhydrater vil blive afskåret. + BS værdi under hvilken insulin er suspenderet. Standard værdi bruger standard målmodel. Bruger kan indstille værdi mellem 60 mg/dl (3,3 mmol/l) og 100 mg/dl (5,5 mmol/l). Værdier under 65/3,6 resulterer i brug af standardmodel Vis notefelt i behandlingsdialoger Næste Forrige @@ -601,7 +606,11 @@ Anden kulhydratstigning Tredje kulhydratstigning CGM + Brug mobilforbindelse + Brug Wi-Fi-forbindelse WiFi SSID + Under opladning + På batteri Indstillinger for forbindelse Tilladte SSID\'er (semikolon separeret) Tillad forbindelse i roaming @@ -677,6 +686,8 @@ En behandling (insulin: %1$.2f, kulhydrater: %2$d, kl: %3$s) kunne ikke tilføjes til behandlinger. Tjek og tilføj venligst en note manuelt efter behov. eCarbs: %1$d g (%2$d h), forsinkelse: %3$d m Ingen tilgængelige autosens data + Logfiler + Diverse Log indstillinger Nulstil til standardindstillinger NSClient funktionsfejl. Overvej NS og NSClient genstart. @@ -769,6 +780,11 @@ Ugyldig angivelse af % Gennemsnit Tid i målområde + Dags TIR + Nat TIR + Detaljerede 14 dage + SD: %1$s + HbA1c: Aktivitetsovervågning Ønsker du at nulstille aktivitetsstatistik? Statistikker @@ -955,6 +971,7 @@ Max-BS udenfor området! Midlertidigt mål:\nMin: %1$s\nMax: %2$s\nVarighed: %3$s Midlertigt mål:\nMål: %1$s\nVarighed: %2$s + Midlertigt mål:\nGrund: %1$s\nMål: %2$s\nVarighed: %3$s Hurtigguide: %1$s\nInsulin: %2$.2fE\nKH: %3$dg Guide:\nInsulin: %1$.2fE\nKH: %2$dg Vis post på enhed: @@ -963,9 +980,11 @@ Ingen aktiv profil angivet! Ukendt COB! BG læsning mangler eller nylig app genstart? KH begrænsninger overtrådt! + Beregner (IC: %1$.1f, ISF: %2$.1f) Kulhydrater: %1$.2fE COB: %1$.0fg %2$.2fE BS: %1$.2fE + IOB: %1$.2fE Superbolus: %1$.2fE 15\' trend: %1$.2fE Procent: %1$.2fE x %2$d%% ≈ %3$.2fE @@ -992,6 +1011,10 @@ %1$d valgt Sortér Dialog annulleret + Meget lav + Lav + Høj + Meget høj Under Inden for området Over @@ -1000,6 +1023,12 @@ AndroidAPS widget Indstil gennemsigtighed Loop status + Graf skala + Profil 1 + Profil 2 + Log ind + Fjern alle + Nulstil start QR-kode til opsætning af engangs kodeord Åbn indstillinger indstil KH alarm @@ -1009,8 +1038,12 @@ kun på ur kun på telefon træk og slip håndtering + Søg GlucoRx Aidex Aidex Modtag BG-værdier fra GlucoRx Aidex CGMS. + Blokeret af opladningsmuligheder + Blokeret af forbindelsesmuligheder + (Intet ur forbundet) diff --git a/app/src/main/res/values-de-rDE/exam.xml b/app/src/main/res/values-de-rDE/exam.xml index 6b25674a29..224325bbe7 100644 --- a/app/src/main/res/values-de-rDE/exam.xml +++ b/app/src/main/res/values-de-rDE/exam.xml @@ -104,9 +104,11 @@ Wo kannst Du nach Hilfe für AndroidAPS suchen? Du kannst in der AndroidAPS-Facebook-Gruppe um Rat bitten. Du solltest die AndroidAPS-Dokumentation lesen (und wiederholt lesen). + Im Discord Channel AndroidAPS kannst Du bei technischen Problemen oder Fragestellungen um Hilfe bitten. Du solltest Deine Diabetesklinik / Deinen Diabetologen fragen. https://androidaps.readthedocs.io/en/latest/CROWDIN/de/Installing-AndroidAPS/Update-to-new-version.html#problembehandlung https://www.facebook.com/groups/loopedDE/ + https://discord.gg/4fQUWHZ4Mw Insulin-Plugins Welches Insulin kann mit dem Ultra-Rapid-Oref-Plugin verwendet werden? Fiasp® @@ -121,6 +123,7 @@ Das Protokollieren eines Kanülenwechsels setzt das Autosens Verhältnis wieder auf 100% zurück. Einige der Plugin-Optionen haben konfigurierbare Zeiträume, die vom Benutzer eingestellt werden können. https://androidaps.readthedocs.io/en/latest/CROWDIN/de/Configuration/Sensitivity-detection-and-COB.html + https://androidaps.readthedocs.io/de/latest/Usage/Open-APS-features.html?highlight=Autosens#autosens Fehler bei der KH-Eingabe Was sollst Du tun, wenn Du einen falschen KH-Eintrag gemacht hast? Lösche die falsche Eingabe in der Behandlung und gib den richtigen neuen Kohlehydratwert ein. @@ -133,6 +136,19 @@ Vergleiche die Werte der Historie in AAPS und Deiner Pumpe (wenn die Pumpe diese Funktion bietet). Gib einen Teil-Bolus des \'nicht erhaltenen\' Insulins mit Spritze / Pen oder durch Befüllen der Kanüle. Unternimm nichts und lass AndroidAPS die entstehenden hohen Glukosewerte korrigieren. + KH an Board (COB) + Wie beeinflusst das Ändern des ISF-Wertes die COB-Berechnung? + Steigende ISF absorbiert Kohlenhydrate länger + Steigende ISF absorbiert Kohlenhydrate kürzer + Steigende ISF verändert die Dauer für die Kohlenhydrataufnahme nicht + Wie beeinflusst das Ändern des ISF-Wertes die COB-Berechnung? + Steigende IC absorbiert Kohlenhydrate länger + Steigende IC absorbiert Kohlenhydrate kürzer + Steigende IC verändert die Zeit für die Kohlenhydrataufnahme nicht + Wie beeinflusst die Änderung des Profil-Prozentsatzes die COB-Berechnung? + Die Einstellung des Profils auf 150% verlängert die Zeit für Kohlenhydrataufnahme + Die Einstellung des Profils auf 150% verkürzt die Zeit für Kohlenhydrataufnahme + Die Einstellung des Profils auf 150% verändert die Zeit für die Kohlenhydrataufnahme nicht Aktives Insulin (IOB) IOB wird von den abgegebenen temporären Basalraten beeinflusst. Eine hohe temporäre Basalrate wird nicht abgegeben, wenn der BZ unterhalb des Zielwerts liegt. diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 94a6d1e3ed..47f2ae35b5 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -6,6 +6,7 @@ Sicherheitseinstellungen der Behandlungen Max. erlaubter Bolus [IE] Max. erlaubte Kohlenhydrate [g] + BG-Pegel, unterhalb dessen die Aussetzung wegen niedriger Glukoseaussetzung eintritt %1$s-Einstellungen Einstellungen Behandlungen von NS aktualisieren @@ -25,6 +26,7 @@ Synchronisiert deine Daten mit Nightscout Stand des Algorithmus in 2017 Der aktuellste Algorithmus für erfahrene Nutzer + Neuester Algorithmus für fortgeschrittene Benutzer mit dynamischer/automatischer ISF Zeigt den aktuellen Status deines Loops und Schaltflächen für die geläufigsten Aktionen an Zeigt eine fortlaufende Benachrichtigung mit einer kurzen Übersicht darüber, was dein Loop derzeit tut Definiere ein Profil, was auch offline verfügbar ist. @@ -264,6 +266,7 @@ KONF LOOP OAPS + DYNISF LP HOME VP @@ -430,12 +433,15 @@ Aktiviere lokale Broadcasts OpenAPS SMB Dynamischer ISF + DynamicISF Anpassungsfaktor % + Anpassungsfaktor für DynamicISF. Stelle mehr als 100 % für aggressivere Korrekturdosen ein, und weniger als 100 % für weniger aggressive Korrekturen. Aktiviere UAM Aktiviere SMB Benutze Super-Mikro-Boli anstelle von temporären Basalraten, um eine schnellere Wirkung zu erreichen. Erkennung von unangekündigten Mahlzeiten Wirkungshoch der IOB-Kurve Wirkungshoch [min] + Gipfel Free-Peak Oref Rapid-Acting Oref Ultra-Rapid Oref @@ -497,6 +503,7 @@ Nur negative COB Berechnung Temporäres Ziel Berechnung + Prozentuale Berechnung Loop aktiviert APS ausgewählt Nightscout-Client hat Schreibrechte @@ -586,6 +593,7 @@ Diesen Wert nennt OpenAPS MaxIOB.\nSolange dieser Wert überschritten wird, wird AndroidAPS kein Insulin abgeben. Maximale Dauer der Essens-Resorption [h] Zeit, nach der jede Mahlzeit mit Sicherheit absorbiert ist. Verbleibende Kohlenhydrate werden danach nicht mehr berücksichtigt. + Der BG-Wert, unter dem die Insulinzuführung ausgesetzt wird. Der Standardwert verwendet das Standard-Zielmodell. Der Benutzer kann einen Wert zwischen 60mg/dl (3.3 mmol/l) und 100mg/dl (5.5mmol/l) setzen. Werte unterhalb 65/3.6 führen zur Verwendung des Standardmodells Zeige Feld für Notizen in den Behandlungsdialogen Weiter Zurück @@ -598,7 +606,11 @@ Zweite KH-Erhöhung Dritte KH-Erhöhung CGM + Mobilfunkverbindung verwenden + WLAN Verbindung verwenden WLAN SSID + Während des Ladevorgangs + Bei Batteriebetrieb Verbindungs-Einstellungen Erlaubte SSIDs (durch Semikolon getrennt) Erlaube Verbindung bei Roaming @@ -656,7 +668,10 @@ Empfindlichkeit erhöht den Zielwert Wenn eine höhere Empfindlichkeit festgestellt wird, wird der Glukose-Zielwert erhöht. \"AndroidAPS gestartet\" Ereignisse löschen + Zeige Ungültige + Verstecke Ungültige Objekte entfernen + Einträge sortieren Gespeicherte Einstellungen gefunden WARNUNG: Wenn Du eine echte Pumpe aktivierst und anschließt, kopiert AndroidAPS die Basaleinstellungen vom aktiven Profil zur Pumpe (und behält sie bei). Die Einstellungen in der Pumpe werden hierbei überschrieben. Wenn Du Dir nicht sicher bist oder die Basaleinstellungen in der Pumpe nicht überschreiben möchten, drücke \"Abbrechen\" und vollziehe den Wechsel zur Pumpe später. Behandlungsdaten unvollständig @@ -671,6 +686,8 @@ Der Eintrag (Insulin: %1$.2f, Kohlenhydrate: %2$d, um: %3$s) konnte nicht als Behandlung gespeichert werden. Bitte überprüfe die aktuelle Liste und füge, falls notwendig, den Datensatz manuell hinzu. eCarbs: %1$d g (%2$d h), Verzögerung: %3$d m Keine Autosens-Daten verfügbar + Log Dateien + Verschiedenes Log-Einstellungen Auf Standardwerte zurücksetzen NSClient Störung. Ziehe einen Neustart von NS und NSClient in Betracht. @@ -764,6 +781,11 @@ Unerwartetes Verhalten. Ungültige % Eingabe Durchschnitt TIR + Tages TIR + Nacht TIR + Detaillierte 14 Tage + SD: %1$s + HbA1c: Aktivitätsmonitor Willst Du die Aktivitätsstatistik zurücksetzen? Statistiken @@ -804,6 +826,7 @@ Unerwartetes Verhalten. Installiere auf jedem Follower-Phone eine Authenticator-App, die RFC 6238 TOTP-Token unterstützt. Beliebte kostenlose Apps sind:\n Authy\n Google Authenticator\n LastPass Authenticator\n FreeOTP Authenticator Wenn Du den Authentifikator zurücksetzt werden alle bestehenden Authentifikatoren ungültig. Du musst sie dann neu einrichten! Predictions (Vorhersagen) + Behandlungen Steigung der Abweichung Autorisierung fehlgeschlagen Gesamtinsulin @@ -873,6 +896,8 @@ Unerwartetes Verhalten. Profilwechsel akzeptieren, die in NS oder NSClient eingegeben wurden APS Offline-Ereignisse empfangen APS Offline-Ereignisse akzeptieren, die über NS oder NSClient eingegeben wurden + TBR und EB empfangen + Akzeptiere TBR und EB, die von einer anderen Instanz eingegeben wurden Insulin abrufen Insulin akzeptieren, das in NS oder NSClient eingegeben wurden Kohlenhydrate abrufen @@ -891,9 +916,11 @@ Unerwartetes Verhalten. Fehler in ISF-Werten %s ausführen? Ungültiges Profil %1$s wurde von NS nicht akzeptiert + Ansicht Fehler Hochladen verlangsamen Status BZ-Daten + BG-Werte entfernen Kanülenalter Alter Patchpumpe Patch-Pumpe @@ -931,7 +958,46 @@ Unerwartetes Verhalten. aktuelles Profil löschen neu zur Liste hinzufügen + Wähle das dunkle, helle oder das Systemdesign + App Farbschema + Dunkles Design + Helles Design + Systemdesign verwenden + Temp-Target unbekannte Voreinstellung: %1$s + Ausführung des Temp-Targets abbrechen? + Verschiedene Einheiten werden auf Uhr und Telefon verwendet! + Zero-Temp-Target - abbrechen des laufenden Temp-Targets? + Min-BG ist außerhalb des Bereichs! + Max-BG ist außerhalb des Bereichs! + Temptarget:\nMin: %1$s\nMax: %2$s\nDauer: %3$s + Temptarget:\nTarget: %1$s\nDauer: %2$s + Temp-Target:\nGrund: %1$s\nTarget: %2$s\nDauer: %3$s + QuickWizard: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg + Calc. Wizard:\nInsulin: %1$.2fU\nCarbs: %2$dg + Zeige Eintrag auf dem Gerät: + Ausgewählter Quickwizard nicht mehr verfügbar, bitte aktualisiere die Kachel + Kein aktueller BG liegt als Basis zur Berechnung vor! + Kein aktives Profil gesetzt! + Unbekannter COB! BG-Wert fehlt oder wurde App vor kurzem neu gestartet? + Die Kohlenhydrateinschränkung wurde überschritten! + Calc (IC: %1$.1f, ISF: %2$.1f) + Kohlenhydrate: %1$.2fU + COB: %1$.0fg %2$.2fU + BZ: %1$.2fU + IOB: %1$.2fU + Superbolus: %1$.2fU + 15\' Trend: %1$.2fU + Prozent: %1$.2fU x %2$d%% ≈ %3$.2fU + Verletzung der Bolusbeschränkung!\nKann %1$.2fU nicht abgeben + TempT: %1$s + %1$s zu %2$s + Keine Pumpe verfügbar! + Unbekannter Actionbefehl: + Prozentsatz + Standardwert der Anwendung + Zeige ungültige / gelöschte Einträge + Verberge ungültige / gelöschte Einträge Profil zum Bearbeiten auswählen Aktualisiere von Nightscout Ausgewähltes Objekt löschen @@ -940,8 +1006,46 @@ Unerwartetes Verhalten. Temporäre Ziele Kohlenhydrate & Bolus Sind Sie sicher, dass Sie diese(s) %1$d Element(e) löschen möchten? + Keine Datensätze verfügbar + Verberge Loop + Zeige Loop an %1$d ausgewählt Sortieren + Dialog abgebrochen + Sehr niedrig + Niedrig + Hoch + Sehr hoch + Unter + Im Zielbereich + Über + Zeige Loop Datensätze + Verberge Loop Datensätze + AndroidAPS Widget + Deckkraft konfigurieren + Loop Status + Diagrammskala + Profil 1 + Profil 2 Login + Alle entfernen + Start zurücksetzen + QR Code für einmaliges Passwort einrichten + Einstellungen öffnen + setze Alarm für KH Timer + Alle + Smartphone + Smartwatch + nur auf Uhr + nur auf Telefon + Drag and Drop Handle + Suche + GlucoRx Aidex + Aidex + Erhalte BG-Werte von GlucoRx Aidex CGMS. + Blockiert durch Ladeoptionen + Blockiert durch Verbindungsoptionen + (keine Uhr verbunden) + Fehler beim Anfordern der Erlaubnis diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index fd5d099938..7cf9ae415d 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -1044,4 +1044,5 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S Bloqué par les options de recharge Bloqué par les options de connectivité (Pas de montre connectée) + Erreur lors de la demande des autorisations diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml index 06dc71b016..b596c03ae4 100644 --- a/app/src/main/res/values-no-rNO/strings.xml +++ b/app/src/main/res/values-no-rNO/strings.xml @@ -1046,4 +1046,5 @@ Blokkert på grunn av ladealternativer Blokkert på grunn av tilkoblingsalternativer (Ingen klokke tilkoblet) + Feil under spørring etter tillatelser diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index fc2d50ec62..27bfd34a25 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -552,7 +552,7 @@ SMB não permitido no modo open loop Alimentos repor - Máximo total IOS OpenAPS não pode superar [U] + Máximo total de IOB OpenAPS não pode superar [U] Este valor é chamado de Max IOB em contexto de OpenAPS\nOpenAPS não adicionará mais insulina se o IOB atual for maior que este valor Tempo máx. absorção refeição [h] Hora em que qualquer refeição é considerada absorvida. Restantes hidratos de carbono serão cortados. diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 48dd372d97..709971fccd 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -1045,4 +1045,5 @@ Заблокировано опциями зарядки Заблокировано настройками подключения (Часы не подключены) + Ошибка при запросе разрешения diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index 3a9f281f95..d2ab919acc 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -1047,4 +1047,5 @@ Aktif Karbonhidratın ne kadar hızlı sindirildiğine ve KŞ\'nin beklenenden d Şarj seçenekleri tarafından engellendi Bağlantı seçenekleri tarafından engellendi (Saat Bağlı Değil) + İzin istenirken hata diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 76a0593fb9..47dd65198e 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -28,6 +28,7 @@ @string/bg_lang @string/cs_lang @string/de_lang + @string/dk_lang @string/fr_lang @string/nl_lang @string/es_lang @@ -55,6 +56,7 @@ bg cs de + dk fr nl es diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d4e11fa7fa..49270f9a76 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,6 +9,7 @@ French German + Danish Greek Chinese @@ -1254,6 +1255,8 @@ Blocked by charging options Blocked by connectivity options (No Watch Connected) - + Error asking for permissions + dynisf_adjust_sensitivity + Adjust sensitivity and BG diff --git a/app/src/main/res/xml/pref_autotune.xml b/app/src/main/res/xml/pref_autotune.xml index aef72365a0..7cc1d6d488 100644 --- a/app/src/main/res/xml/pref_autotune.xml +++ b/app/src/main/res/xml/pref_autotune.xml @@ -1,6 +1,8 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:validate="http://schemas.android.com/apk/res-auto"> + --> - + android:title="@string/autotune_default_tune_days_title" + android:dialogMessage="@string/autotune_default_tune_days_summary" + android:digits="0123456789" + android:inputType="number" + android:selectAllOnFocus="true" + android:singleLine="true" + validate:maxNumber="30" + validate:minNumber="1" + validate:testType="numericRange" /> + android:key="@string/key_adjust_sensitivity" + android:title="@string/dynisf_adjust_sensitivity" /> Kør automatisering Tilføj regel Fjern/sorter + Stop afvikling diff --git a/automation/src/main/res/values-de-rDE/strings.xml b/automation/src/main/res/values-de-rDE/strings.xml index 4fdf548bc7..c6e3b2bc69 100644 --- a/automation/src/main/res/values-de-rDE/strings.xml +++ b/automation/src/main/res/values-de-rDE/strings.xml @@ -113,5 +113,15 @@ Automatisierungs-Ereignis Umsortieren Benutzeraktion + Automatisierung entfernen + Automation-Regeln sortieren + Ausgewähltes Objekt löschen + %1$d ausgewählt Sind Sie sicher, dass Sie diese(s) %1$d Element(e) löschen möchten? + Sortieren + System-Automatisierung + Automatisierungen ausführen + Regel hinzufügen + Entfernen/sortieren + Verarbeitung beenden diff --git a/automation/src/main/res/values-ru-rRU/strings.xml b/automation/src/main/res/values-ru-rRU/strings.xml index d91dd62b17..ec29696bf0 100644 --- a/automation/src/main/res/values-ru-rRU/strings.xml +++ b/automation/src/main/res/values-ru-rRU/strings.xml @@ -90,7 +90,7 @@ Широта: Долгота: Гк %1$s]: - Цель %1$d м + Цель [%1$s]: Предыдущий болюс Время болюса %1$s %2$s мин назад Активн углеводы diff --git a/automation/src/main/res/values-sk-rSK/strings.xml b/automation/src/main/res/values-sk-rSK/strings.xml index 39a1502bc1..13e9c9d977 100644 --- a/automation/src/main/res/values-sk-rSK/strings.xml +++ b/automation/src/main/res/values-sk-rSK/strings.xml @@ -123,4 +123,5 @@ Spustiť automatizácie Pridať pravidlo Odstrániť/zoradiť + Zastaviť spracovanie diff --git a/build.gradle b/build.gradle index 5aafa2b9ae..b2dfbd702d 100644 --- a/build.gradle +++ b/build.gradle @@ -7,14 +7,14 @@ buildscript { rxjava_version = '3.1.5' rxandroid_version = '3.0.0' rxkotlin_version = '3.0.1' - room_version = '2.4.2' + room_version = '2.4.3' lifecycle_version = '2.5.0' dagger_version = '2.42' coroutines_version = '1.6.4' activity_version = '1.4.0' fragmentktx_version = '1.4.1' ormLite_version = '4.46' - gson_version = '2.9.0' + gson_version = '2.9.1' nav_version = '2.4.2' appcompat_version = '1.4.2' material_version = '1.6.1' @@ -48,7 +48,7 @@ buildscript { maven { url "https://plugins.gradle.org/m2/" } // jacoco 0.2 } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:7.2.2' classpath 'com.google.gms:google-services:4.3.13' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' diff --git a/combo/src/main/res/values-de-rDE/strings.xml b/combo/src/main/res/values-de-rDE/strings.xml index f932cf9292..32fa737274 100644 --- a/combo/src/main/res/values-de-rDE/strings.xml +++ b/combo/src/main/res/values-de-rDE/strings.xml @@ -51,4 +51,10 @@ Anzahl TBR Bolus gestoppt Bolus wird gestoppt + Komm. Fehleranzahl + Zeige Komm.-Fehleranzahl + Zeigt die Fehleranzahl bei der Kommunikation mit Ruffy an. In den meisten Fällen zeigt eine Zahl höher als 0 an, dass Ruffy Kommunikationsprobleme vorliegen (ein Neustart kann erforderlich sein). + Nie + Bei Fehler + Immer diff --git a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStore.kt b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStore.kt index 5d65bae4e8..c62250c04a 100644 --- a/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStore.kt +++ b/core/src/main/java/info/nightscout/androidaps/plugins/iob/iobCobCalculator/AutosensDataStore.kt @@ -1,6 +1,7 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator import androidx.collection.LongSparseArray +import androidx.collection.size import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.data.InMemoryGlucoseValue import info.nightscout.androidaps.database.AppRepository @@ -41,7 +42,7 @@ class AutosensDataStore { AutosensDataStore().also { synchronized(dataLock) { it.bgReadings = this.bgReadings.toMutableList() - it.autosensDataTable = this.autosensDataTable.clone() + it.autosensDataTable = LongSparseArray(this.autosensDataTable.size).apply { putAll(this@AutosensDataStore.autosensDataTable) } it.bucketedData = this.bucketedData?.toMutableList() } } @@ -57,7 +58,7 @@ class AutosensDataStore { synchronized(autosensDataTable) { for (index in autosensDataTable.size() - 1 downTo 0) { if (autosensDataTable.keyAt(index) > time) { - aapsLogger.debug(LTag.AUTOSENS, "Removing from autosensDataTable: " + dateUtil.dateAndTimeAndSecondsString(autosensDataTable.keyAt(index))) + aapsLogger.debug(LTag.AUTOSENS) { "Removing from autosensDataTable: ${dateUtil.dateAndTimeAndSecondsString(autosensDataTable.keyAt(index))}" } autosensDataTable.removeAt(index) } else { break @@ -135,10 +136,10 @@ class AutosensDataStore { return null } return if (data.time < System.currentTimeMillis() - 11 * 60 * 1000) { - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA null: data is old (" + reason + ") size()=" + autosensDataTable.size() + " lastData=" + dateUtil.dateAndTimeAndSecondsString(data.time)) + aapsLogger.debug(LTag.AUTOSENS) { "AUTOSENSDATA null: data is old ($reason) size()=${autosensDataTable.size()} lastData=${dateUtil.dateAndTimeAndSecondsString(data.time)}" } null } else { - aapsLogger.debug(LTag.AUTOSENS, "AUTOSENSDATA ($reason) $data") + aapsLogger.debug(LTag.AUTOSENS) { "AUTOSENSDATA ($reason) $data" } data } } @@ -164,7 +165,7 @@ class AutosensDataStore { .compatGetBgReadingsDataFromTime(start, to + T.mins(2).msecs(), false) .blockingGet() .filter { it.value >= 39 } - aapsLogger.debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to)) + aapsLogger.debug(LTag.AUTOSENS) { "BG data loaded. Size: ${bgReadings.size} Start date: ${dateUtil.dateAndTimeString(start)} End date: ${dateUtil.dateAndTimeString(to)}" } createBucketedData(aapsLogger, dateUtil) rxBus.send(EventBucketedDataCreated()) } @@ -184,13 +185,13 @@ class AutosensDataStore { totalDiff += diff diff = abs(diff) if (diff > T.secs(30).msecs()) { - aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " diff: " + diff / 1000 + "[s] is5minData: " + false) + aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: ${bgReadings.size} diff: ${diff / 1000}[s] is5minData: false") return false } } val averageDiff = totalDiff / bgReadings.size / 1000 val is5minData = averageDiff < 1 - aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: " + bgReadings.size + " averageDiff: " + averageDiff + "[s] is5minData: " + is5minData) + aapsLogger.debug(LTag.AUTOSENS, "Interval detection: values: ${bgReadings.size} averageDiff: $averageDiff[s] is5minData: $is5minData") return is5minData } } @@ -239,8 +240,7 @@ class AutosensDataStore { var currentTime = bgReadings[0].timestamp - bgReadings[0].timestamp % T.mins(5).msecs() val adjustedTime = adjustToReferenceTime(currentTime) // after adjusting time may be newer. In this case use T-5min - if (adjustedTime > currentTime) currentTime = adjustedTime - T.mins(5).msecs() - else currentTime = adjustedTime + currentTime = if (adjustedTime > currentTime) adjustedTime - T.mins(5).msecs() else adjustedTime aapsLogger.debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime)) //log.debug("First reading: " + new Date(currentTime).toLocaleString()); while (true) { @@ -270,7 +270,7 @@ class AutosensDataStore { } val bData: MutableList = ArrayList() bData.add(InMemoryGlucoseValue(bgReadings[0])) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgReadings[0].timestamp) + " lastBgTime: " + "none-first-value" + " " + bgReadings[0].toString()) + aapsLogger.debug(LTag.AUTOSENS) { "Adding. bgTime: ${dateUtil.toISOString(bgReadings[0].timestamp)} lastBgTime: none-first-value ${bgReadings[0]}" } var j = 0 for (i in 1 until bgReadings.size) { val bgTime = bgReadings[i].timestamp @@ -293,7 +293,7 @@ class AutosensDataStore { val newBgReading = InMemoryGlucoseValue(nextBgTime, nextBg.roundToLong().toDouble(), true) //console.error("Interpolated", bData[j]); bData.add(newBgReading) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgTime) + " lastBgTime: " + dateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) + aapsLogger.debug(LTag.AUTOSENS) { "Adding. bgTime: ${dateUtil.toISOString(bgTime)} lastBgTime: ${dateUtil.toISOString(lastBgTime)} $newBgReading" } elapsedMinutes -= 5 lastBg = nextBg lastBgTime = nextBgTime @@ -301,14 +301,14 @@ class AutosensDataStore { j++ val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value) bData.add(newBgReading) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgTime) + " lastBgTime: " + dateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) + aapsLogger.debug(LTag.AUTOSENS) { "Adding. bgTime: ${dateUtil.toISOString(bgTime)} lastBgTime: ${dateUtil.toISOString(lastBgTime)} $newBgReading" } } abs(elapsedMinutes) > 2 -> { j++ val newBgReading = InMemoryGlucoseValue(bgTime, bgReadings[i].value) bData.add(newBgReading) - aapsLogger.debug(LTag.AUTOSENS, "Adding. bgTime: " + dateUtil.toISOString(bgTime) + " lastBgTime: " + dateUtil.toISOString(lastBgTime) + " " + newBgReading.toString()) + aapsLogger.debug(LTag.AUTOSENS) { "Adding. bgTime: ${dateUtil.toISOString(bgTime)} lastBgTime: ${dateUtil.toISOString(lastBgTime)} $newBgReading" } } else -> { @@ -327,7 +327,7 @@ class AutosensDataStore { val previous = bData[i + 1] val mSecDiff = current.timestamp - previous.timestamp val adjusted = (mSecDiff - T.mins(5).msecs()) / 1000 - aapsLogger.debug(LTag.AUTOSENS, "Adjusting bucketed data time. Current: " + dateUtil.dateAndTimeAndSecondsString(current.timestamp) + " to: " + dateUtil.dateAndTimeAndSecondsString(previous.timestamp + T.mins(5).msecs()) + " by " + adjusted + " sec") + aapsLogger.debug(LTag.AUTOSENS) { "Adjusting bucketed data time. Current: ${dateUtil.dateAndTimeAndSecondsString(current.timestamp)} to: ${dateUtil.dateAndTimeAndSecondsString(previous.timestamp + T.mins(5).msecs())} by $adjusted sec" } if (abs(adjusted) > 90) { // too big adjustment, fallback to non 5 min data aapsLogger.debug(LTag.AUTOSENS, "Fallback to non 5 min data") @@ -354,5 +354,4 @@ class AutosensDataStore { } return if (count != 0) sum / count else 0.0 } - } \ No newline at end of file diff --git a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt index 5fbe786c73..8b10cb6a97 100644 --- a/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt +++ b/core/src/main/java/info/nightscout/androidaps/services/AlarmSoundService.kt @@ -74,7 +74,7 @@ class AlarmSoundService : DaggerService() { if (intent?.hasExtra(ErrorHelperActivity.SOUND_ID) == true) resourceId = intent.getIntExtra(ErrorHelperActivity.SOUND_ID, R.raw.error) player = MediaPlayer() try { - val afd = rh.openRawResourceFd(resourceId) ?: return START_STICKY + val afd = rh.openRawResourceFd(resourceId) ?: return START_NOT_STICKY player?.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length) afd.close() player?.isLooping = true @@ -94,7 +94,7 @@ class AlarmSoundService : DaggerService() { aapsLogger.error("Unhandled exception", e) } aapsLogger.debug(LTag.CORE, "onStartCommand End") - return START_STICKY + return START_NOT_STICKY } override fun onDestroy() { diff --git a/core/src/main/res/values-da-rDK/strings.xml b/core/src/main/res/values-da-rDK/strings.xml index 013f43fc61..2b88c0a550 100644 --- a/core/src/main/res/values-da-rDK/strings.xml +++ b/core/src/main/res/values-da-rDK/strings.xml @@ -450,17 +450,23 @@ Hvis aktiveret, vil Autotune automatisk opdatere og skifte til input-profil efter beregning ud fra en automatiseringsregel. Kategoriser UAM som basal Aktiver kun hvis du har indtastet alle kulhydrater på pålidelig vis. Med denne indstilling vil pludselige stigninger set af Autotune, blive brugt til at anbefale ændringer af basal rate. + Tilpas insulinkurven + Aktiver kun hvis du bruger egen peak værdi. Dette alternativ vil justere peak og DIA-varigheden Antal dage med data Anvend gennemsnitligt resultat i døgnbaseret IC/ISF Autotune vil ikke justere døgnrytme variationer, denne indstilling benytter gennemsnitlige værdier til justering af IC og ISF til din døgnrytme input profil Inkludér flere logoplysninger for fejlfinding Aktivér kun hvis udviklerne beder dig om det, for at sende flere logoplysninger til at hjælpe med at fejlfinde Autotune plugin + Standard antal dage data der skal behandles af Autotune (op til 30) Justeret Profil : Justerings dage : Sidst kørt : Advarsel : Vælg profil, der skal justeres + Autotune fungerer med kun én IC-værdi, din profil har %1$d værdier. Gennemsnitsværdi er %2$.2fg/E + Autotune virker med kun én ISF-værdi, din profil har %1$d værdier. Gennemsnitlig værdi er %2$.1f%3$s/E + Fejl i inputdata, prøv at køre autotune igen eller reducer antallet af dage Automatisk beregning startet, vær venligst tålmodig Kontrollér resultaterne omhyggeligt, før du bruger dem! Delvis resultat dag %1$d / %2$d justeret @@ -482,6 +488,7 @@ Autotune kørt uden profilskift Autotune kørt, profilen er automatisk skiftet Fejl under sidste Autotune kørsel + Autotune kører allerede, annulleret Applikationen kræver tilladelse til bluetooth %1$d dag diff --git a/core/src/main/res/values-de-rDE/strings.xml b/core/src/main/res/values-de-rDE/strings.xml index 400da03d56..6932c25155 100644 --- a/core/src/main/res/values-de-rDE/strings.xml +++ b/core/src/main/res/values-de-rDE/strings.xml @@ -135,7 +135,9 @@ Auf neueren Geräten muss für die Bluetooth-Erkennung der Standortdienst aktiviert sein. AAPS speichert keine Standortdaten und der Dienst kann nach erfolgreichem Pairing wieder deaktiviert werden. Falsches Passwort + Falsche PIN Die Passwörter stimmen nicht überein. + PINs stimmen nicht überein Basalraten beginnen nicht zur vollen Stunde: %1$s Basal-Wert wurde durch den kleinst möglichen Wert ersetzt: %1$s @@ -429,10 +431,64 @@ Insight Refresh Button abnehmend %1$s mit %2$s zunehmend %1$s mit %2$s + %1$.0f%% Basal + Basal % %1$d ausgewählt Sortieren + Entferne Elemente + Sortiere Elemente + lösche ausgewählte Elemente + Datei + Nutzer + Autotune + Hilfe bei möglichen Anpassungen des Profils (ISF, IC und Basalraten) + AT + Autotune Einstellungen + Automation Profilwechsel + Falls aktiviert, wird Autotune nach der Berechnung in einer Automatisierungsregel automatisch das Eingangsprofil anpassen und darauf wechseln. + UAM als Basal kategorisieren + Nur aktivieren, wenn Sie alle gegessen Kohlenhydrate zuverlässig eingegeben haben. Mit dieser Option werden plötzliche Steigerungen, die durch Autotune entdeckt werden, verwendet, um Änderungen an der Basalrate zu empfehlen. + Insulinkurve anpassen + Nur einschalten, falls Du Free Peak verwendest. Diese Option passt sowohl den Gipfel der Wirkkurve an als auch die DIA Laufzeit + Anzahl der Tage an Daten + Durchschnittsresultat im zirkadianen IC/ISF anwenden + Autotune wird keine zirkadianen Variationen einstellen. Diese Option wendet nur die durchschnittliche Änderung von IC und ISF auf Dein zirkadianes Eingangsprofil an + Fügen Sie weitere Log-Informationen zum Debuggen ein + Nur einschalten, wenn von Du von den Entwicklern aufgefordert wirst, um ausführlichere Protokollinformationen zu senden, die beim Debuggen des Autotune Plugins hilfreich sind + Standardanzahl der von Autotune zu verarbeitenden Daten (bis zu 30) + Angepasst + Profil : + Anpassungstage : + Letzte Ausführung : + Warnung : + Wähle das Profil zum Anpassen aus + Ausgewähltes Profil hat %1$d IC-Werte. Autotune wird %2$.2f g/U verwenden + Ausgewähltes Profil hat %1$d ISF-Werte. Autotune wird %2$.1f %3$s/U verwenden + Fehler in den Eingabedaten, versuche erneut Autotune auszuführen oder reduziere die Anzahl der Tage + Autotune Berechnung gestartet, bitte gedulde Dich einen Moment + Überprüfe die Ergebnisse sorgfältig, bevor Du sie verwendest! + Teilergebnistag %1$d / %2$d angepasst + Ergebnis: %1$s + Parameter + % + Fehlend + Autotune Profil %1$s + Autotune ausführen + Eingabeprofil überprüfen + Profile vergleichen + In lokales Profil kopieren + Eingabeprofil anpassen + Eingabeprofil zurücksetzen + Neues lokales Profil aus diesem Autotune Profil erstellen? + Anpassen %1$s Profile mit dem Autotune Profile? + %1$s Profil mit Eingabeprofil zurücksetzen? + Profil ungültig + Autotune ohne Profilwechsel ausgeführt + Autotune ausgeführt und Profil automatisch gewechselt + Fehler beim letzten Autotune Lauf + Ein weiterer Lauf von Autotune wurde erkannt, Lauf abgebrochen App benötigt Bluetooth-Berechtigung %1$d Tag diff --git a/core/src/main/res/values-fr-rFR/strings.xml b/core/src/main/res/values-fr-rFR/strings.xml index cfd4038982..9d13c4bb50 100644 --- a/core/src/main/res/values-fr-rFR/strings.xml +++ b/core/src/main/res/values-fr-rFR/strings.xml @@ -489,6 +489,7 @@ Autotune exécuté et le profil automatiquement activé Erreur lors de la dernière exécution d\'Autotune Une autre exécution d\'Autotune est détectée, l\'exécution est annulée + L\'application a besoin de l\'autorisation Bluetooth %1$d jour %1$d jours diff --git a/core/src/main/res/values-night/styles.xml b/core/src/main/res/values-night/styles.xml index 3a9fe781b5..dfd244db24 100644 --- a/core/src/main/res/values-night/styles.xml +++ b/core/src/main/res/values-night/styles.xml @@ -248,6 +248,8 @@ @color/white @style/CommonSpinnerItemStyle + + @style/GrayButton diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml index 0c9e53b9b7..5c5146e42d 100644 --- a/core/src/main/res/values/attrs.xml +++ b/core/src/main/res/values/attrs.xml @@ -218,4 +218,6 @@ + + \ No newline at end of file diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index b831de330c..a471a947dc 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -249,6 +249,8 @@ @color/white @style/CommonSpinnerItemStyle + + @style/GrayButton