diff --git a/app/build.gradle b/app/build.gradle index 9740cf7335..b7600175b6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,7 +44,7 @@ android { minSdkVersion 21 targetSdkVersion 23 versionCode 1100 - versionName "1.1" + versionName "1.1c" buildConfigField "String", "BUILDVERSION", generateGitBuild() } lintOptions { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d49ee22092..58cdb693a1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,6 +36,8 @@ + + diff --git a/app/src/main/java/info/nightscout/androidaps/Constants.java b/app/src/main/java/info/nightscout/androidaps/Constants.java index adcb7a883f..959e4fd6ee 100644 --- a/app/src/main/java/info/nightscout/androidaps/Constants.java +++ b/app/src/main/java/info/nightscout/androidaps/Constants.java @@ -42,4 +42,23 @@ public class Constants { // Circadian Percentage Profile public static final int CPP_MIN_PERCENTAGE = 50; public static final int CPP_MAX_PERCENTAGE = 200; + + + public static final String MAX_BG_DEFAULT_MGDL = "180"; + public static final String MAX_BG_DEFAULT_MMOL = "10"; + public static final String MIN_BG_DEFAULT_MGDL = "100"; + public static final String MIN_BG_DEFAULT_MMOL = "5"; + public static final String TARGET_BG_DEFAULT_MGDL = "150"; + public static final String TARGET_BG_DEFAULT_MMOL = "7"; + + // Very Hard Limits Ranges + // First value is the Lowest and second value is the Highest a Limit can define + public static final int[] VERY_HARD_LIMIT_MIN_BG = {72,180}; + public static final int[] VERY_HARD_LIMIT_MAX_BG = {99,270}; + public static final int[] VERY_HARD_LIMIT_TARGET_BG = {80,200}; + + // Very Hard Limits Ranges for Temp Targets + public static final int[] VERY_HARD_LIMIT_TEMP_MIN_BG = {72,180}; + public static final int[] VERY_HARD_LIMIT_TEMP_MAX_BG = {72,270}; + public static final int[] VERY_HARD_LIMIT_TEMP_TARGET_BG = {72,200}; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java index d0acb2a3b4..00de620ba1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java @@ -370,6 +370,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick String enteredBy = SP.getString("careportal_enteredby", ""); JSONObject data = new JSONObject(); try { + boolean allowZeroDuration = false; data.put("created_at", DateUtil.toISOString(eventTime)); switch (options.eventType) { case R.id.careportal_bgcheck: @@ -431,6 +432,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick break; case R.id.careportal_temptarget: data.put("eventType", "Temporary Target"); + allowZeroDuration = true; break; } if (SafeParse.stringToDouble(bgInputEdit.getText().toString()) != 0d) { @@ -443,7 +445,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick data.put("carbs", SafeParse.stringToDouble(carbsEdit.getText().toString())); if (SafeParse.stringToDouble(insulinEdit.getText().toString()) != 0d) data.put("insulin", SafeParse.stringToDouble(insulinEdit.getText().toString())); - if (SafeParse.stringToDouble(durationeEdit.getText().toString()) != 0d) + if (allowZeroDuration || SafeParse.stringToDouble(durationeEdit.getText().toString()) != 0d) data.put("duration", SafeParse.stringToDouble(durationeEdit.getText().toString())); if (layoutPercent.getVisibility() != View.GONE) data.put("percent", SafeParse.stringToDouble(percentEdit.getText().toString())); @@ -607,30 +609,41 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick ConfigBuilderPlugin.uploadCareportalEntryToNS(data); } if (options.executeTempTarget) { - if (data.has("targetBottom") && data.has("targetTop")) { - sHandler.post(new Runnable() { - @Override - public void run() { - try { - TempTarget tempTarget = new TempTarget(); - tempTarget.timeStart = eventTime; - tempTarget.duration = data.getInt("duration"); - tempTarget.reason = data.getString("reason"); - tempTarget.low = NSProfile.toMgdl(data.getDouble("targetBottom"), MainApp.getConfigBuilder().getActiveProfile().getProfile().getUnits()); - tempTarget.high = NSProfile.toMgdl(data.getDouble("targetTop"), MainApp.getConfigBuilder().getActiveProfile().getProfile().getUnits()); - tempTarget.setTimeIndex(tempTarget.getTimeIndex()); - Dao dao = MainApp.getDbHelper().getDaoTempTargets(); - log.debug("Creating new TempTarget db record: " + tempTarget.log()); - dao.createIfNotExists(tempTarget); - MainApp.bus().post(new EventTempTargetRangeChange()); - ConfigBuilderPlugin.uploadCareportalEntryToNS(data); - } catch (JSONException e) { - e.printStackTrace(); - } catch (SQLException e) { - e.printStackTrace(); + + + try { + if ((data.has("targetBottom") && data.has("targetTop")) || (data.has("duration")&& data.getInt("duration") == 0)) { + sHandler.post(new Runnable() { + @Override + public void run() { + try { + TempTarget tempTarget = new TempTarget(); + tempTarget.timeStart = eventTime; + tempTarget.duration = data.getInt("duration"); + tempTarget.reason = data.getString("reason"); + if(tempTarget.duration != 0) { + tempTarget.low = NSProfile.toMgdl(data.getDouble("targetBottom"), MainApp.getConfigBuilder().getActiveProfile().getProfile().getUnits()); + tempTarget.high = NSProfile.toMgdl(data.getDouble("targetTop"), MainApp.getConfigBuilder().getActiveProfile().getProfile().getUnits()); + } else { + tempTarget.low = 0; + tempTarget.high = 0; + } + tempTarget.setTimeIndex(tempTarget.getTimeIndex()); + Dao dao = MainApp.getDbHelper().getDaoTempTargets(); + log.debug("Creating new TempTarget db record: " + tempTarget.log()); + dao.createIfNotExists(tempTarget); + MainApp.bus().post(new EventTempTargetRangeChange()); + ConfigBuilderPlugin.uploadCareportalEntryToNS(data); + } catch (JSONException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } } - } - }); + }); + } + } catch (JSONException e) { + e.printStackTrace(); } } else { ConfigBuilderPlugin.uploadCareportalEntryToNS(data); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java index b7fae2a125..9fa77e0e17 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRFragment.java @@ -29,6 +29,7 @@ import info.nightscout.androidaps.events.EventTempBasalChange; import info.nightscout.androidaps.interfaces.FragmentBase; import info.nightscout.androidaps.plugins.DanaR.Dialogs.ProfileViewDialog; import info.nightscout.androidaps.plugins.DanaR.History.DanaRHistoryActivity; +import info.nightscout.androidaps.plugins.DanaR.History.DanaRStatsActivity; import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus; import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRNewStatus; import info.nightscout.utils.DateUtil; @@ -65,6 +66,8 @@ public class DanaRFragment extends Fragment implements FragmentBase { TextView iobView; Button viewProfileButton; Button historyButton; + Button statsButton; + public DanaRFragment() { if (sHandlerThread == null) { @@ -105,6 +108,8 @@ public class DanaRFragment extends Fragment implements FragmentBase { iobView = (TextView) view.findViewById(R.id.danar_iob); viewProfileButton = (Button) view.findViewById(R.id.danar_viewprofile); historyButton = (Button) view.findViewById(R.id.danar_history); + statsButton = (Button) view.findViewById(R.id.danar_stats); + viewProfileButton.setOnClickListener(new View.OnClickListener() { @Override @@ -122,6 +127,13 @@ public class DanaRFragment extends Fragment implements FragmentBase { } }); + statsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(getContext(), DanaRStatsActivity.class)); + } + }); + btConnectionView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java index 72a7a74248..9e4a658e65 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/DanaRPlugin.java @@ -252,7 +252,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, ConstraintsInterf for (int h = 0; h < basalValues; h++) { Double pumpValue = pump.pumpProfiles[pump.activeProfile][h]; Double profileValue = profile.getBasal(h * basalIncrement); - if (!pumpValue.equals(profileValue)) { + if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) { log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue); return false; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/History/DanaRStatsActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/History/DanaRStatsActivity.java new file mode 100644 index 0000000000..4e75c4c999 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaR/History/DanaRStatsActivity.java @@ -0,0 +1,570 @@ +package info.nightscout.androidaps.plugins.DanaR.History; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.support.v7.widget.LinearLayoutManager; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.stmt.PreparedQuery; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.stmt.Where; +import com.squareup.otto.Subscribe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.SQLException; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.db.DanaRHistoryRecord; +import info.nightscout.androidaps.interfaces.ProfileInterface; +import info.nightscout.androidaps.plugins.CircadianPercentageProfile.CircadianPercentageProfilePlugin; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.DanaR.Services.ExecutionService; +import info.nightscout.androidaps.plugins.DanaR.comm.RecordTypes; +import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus; +import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRSyncStatus; +import info.nightscout.utils.DecimalFormatter; +import info.nightscout.utils.ToastUtils; + +public class DanaRStatsActivity extends Activity { + private static Logger log = LoggerFactory.getLogger(DanaRStatsActivity.class); + + private boolean mBounded; + private static ExecutionService mExecutionService; + + private Handler mHandler; + private static HandlerThread mHandlerThread; + + TextView statusView, statsMessage,totalBaseBasal2; + EditText totalBaseBasal; + Button reloadButton; + LinearLayoutManager llm; + TableLayout tl,ctl,etl; + String TBB; + double magicNumber; + DecimalFormat decimalFormat; + + List historyList = new ArrayList<>(); + + public DanaRStatsActivity() { + super(); + mHandlerThread = new HandlerThread(DanaRStatsActivity.class.getSimpleName()); + mHandlerThread.start(); + this.mHandler = new Handler(mHandlerThread.getLooper()); + } + + @Override + public void onStart() { + super.onStart(); + Intent intent = new Intent(this, ExecutionService.class); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onResume() { + super.onResume(); + MainApp.bus().register(this); + } + + @Override + protected void onPause() { + super.onPause(); + MainApp.bus().unregister(this); + } + + @Override + public void onStop() { + super.onStop(); + if (mBounded) { + unbindService(mConnection); + mBounded = false; + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + View myView = getCurrentFocus(); + if ( myView instanceof EditText) { + Rect rect = new Rect(); + myView.getGlobalVisibleRect(rect); + if (!rect.contains((int)event.getRawX(), (int)event.getRawY())) { + myView.clearFocus(); + } + } + } + return super.dispatchTouchEvent( event ); + } + + ServiceConnection mConnection = new ServiceConnection() { + + public void onServiceDisconnected(ComponentName name) { + log.debug("Service is disconnected"); + mBounded = false; + mExecutionService = null; + } + + public void onServiceConnected(ComponentName name, IBinder service) { + log.debug("Service is connected"); + mBounded = true; + ExecutionService.LocalBinder mLocalBinder = (ExecutionService.LocalBinder) service; + mExecutionService = mLocalBinder.getServiceInstance(); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.danar_statsactivity); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + statusView = (TextView) findViewById(R.id.danar_stats_connection_status); + reloadButton = (Button) findViewById(R.id.danar_statsreload); + totalBaseBasal = (EditText) findViewById(R.id.danar_stats_editTotalBaseBasal); + totalBaseBasal2 = (TextView) findViewById(R.id.danar_stats_editTotalBaseBasal2); + statsMessage = (TextView) findViewById(R.id.danar_stats_Message); + + statusView.setVisibility(View.GONE); + statsMessage.setVisibility(View.GONE); + + totalBaseBasal2.setEnabled(false); + totalBaseBasal2.setClickable(false); + totalBaseBasal2.setFocusable(false); + totalBaseBasal2.setInputType(0); + + decimalFormat = new DecimalFormat("0.000"); + llm = new LinearLayoutManager(this); + + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + TBB = preferences.getString("TBB", "10.00"); + totalBaseBasal.setText(TBB); + + ProfileInterface pi = ConfigBuilderPlugin.getActiveProfile(); + if (pi != null && pi instanceof CircadianPercentageProfilePlugin){ + double cppTBB = ((CircadianPercentageProfilePlugin)pi).baseBasalSum(); + totalBaseBasal.setText(decimalFormat.format(cppTBB)); + SharedPreferences.Editor edit = preferences.edit(); + edit.putString("TBB",totalBaseBasal.getText().toString()); + edit.commit(); + TBB = preferences.getString("TBB", ""); + } + + // stats table + tl = (TableLayout) findViewById(R.id.main_table); + TableRow tr_head = new TableRow(this); + tr_head.setBackgroundColor(Color.DKGRAY); + tr_head.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + TextView label_date = new TextView(this); + label_date.setText(getString(R.string.danar_stats_date)); + label_date.setTextColor(Color.WHITE); + tr_head.addView(label_date); + + TextView label_basalrate = new TextView(this); + label_basalrate.setText(getString(R.string.danar_stats_basalrate)); + label_basalrate.setTextColor(Color.WHITE); + tr_head.addView(label_basalrate); + + TextView label_bolus = new TextView(this); + label_bolus.setText(getString(R.string.danar_stats_bolus)); + label_bolus.setTextColor(Color.WHITE); + tr_head.addView(label_bolus); + + TextView label_tdd = new TextView(this); + label_tdd.setText(getString(R.string.danar_stats_tdd)); + label_tdd.setTextColor(Color.WHITE); + tr_head.addView(label_tdd); + + TextView label_ratio = new TextView(this); + label_ratio.setText(getString(R.string.danar_stats_ratio)); + label_ratio.setTextColor(Color.WHITE); + tr_head.addView(label_ratio); + + // add stats headers to tables + tl.addView(tr_head, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // cumulative table + ctl = (TableLayout) findViewById(R.id.cumulative_table); + TableRow ctr_head = new TableRow(this); + ctr_head.setBackgroundColor(Color.DKGRAY); + ctr_head.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + TextView label_cum_amount_days = new TextView(this); + label_cum_amount_days.setText(getString(R.string.danar_stats_amount_days)); + label_cum_amount_days.setTextColor(Color.WHITE); + ctr_head.addView(label_cum_amount_days); + + TextView label_cum_tdd = new TextView(this); + label_cum_tdd.setText(getString(R.string.danar_stats_tdd)); + label_cum_tdd.setTextColor(Color.WHITE); + ctr_head.addView(label_cum_tdd); + + TextView label_cum_ratio = new TextView(this); + label_cum_ratio.setText(getString(R.string.danar_stats_ratio)); + label_cum_ratio.setTextColor(Color.WHITE); + ctr_head.addView(label_cum_ratio); + + // add cummulative headers to tables + ctl.addView(ctr_head, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // expontial table + etl = (TableLayout) findViewById(R.id.expweight_table); + TableRow etr_head = new TableRow(this); + etr_head.setBackgroundColor(Color.DKGRAY); + etr_head.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + TextView label_exp_weight = new TextView(this); + label_exp_weight.setText(getString(R.string.danar_stats_weight)); + label_exp_weight.setTextColor(Color.WHITE); + etr_head.addView(label_exp_weight); + + TextView label_exp_tdd = new TextView(this); + label_exp_tdd.setText(getString(R.string.danar_stats_tdd)); + label_exp_tdd.setTextColor(Color.WHITE); + etr_head.addView(label_exp_tdd); + + TextView label_exp_ratio = new TextView(this); + label_exp_ratio.setText(getString(R.string.danar_stats_ratio)); + label_exp_ratio.setTextColor(Color.WHITE); + etr_head.addView(label_exp_ratio); + + // add expontial headers to tables + etl.addView(etr_head, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + reloadButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mExecutionService.isConnected() || mExecutionService.isConnecting()) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.pumpbusy)); + return; + } + mHandler.post(new Runnable() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + reloadButton.setVisibility(View.GONE); + statusView.setVisibility(View.VISIBLE); + statsMessage.setVisibility(View.VISIBLE); + statsMessage.setText(getString(R.string.danar_stats_warning_Message)); + } + }); + mExecutionService.loadHistory(RecordTypes.RECORD_TYPE_DAILY); + loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); + runOnUiThread(new Runnable() { + @Override + public void run() { + reloadButton.setVisibility(View.VISIBLE); + statusView.setVisibility(View.GONE); + statsMessage.setVisibility(View.GONE); + } + }); + } + }); + } + }); + + totalBaseBasal.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if(actionId== EditorInfo.IME_ACTION_DONE){ + totalBaseBasal.clearFocus(); + return true; + } + return false; + } + }); + + totalBaseBasal.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if(hasFocus){ + totalBaseBasal.getText().clear(); + } else { + SharedPreferences.Editor edit = preferences.edit(); + edit.putString("TBB",totalBaseBasal.getText().toString()); + edit.commit(); + TBB = preferences.getString("TBB", ""); + loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); + InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(totalBaseBasal.getWindowToken(), 0); + } + } + }); + + loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); + } + + private void loadDataFromDB(byte type) { + try { + Dao dao = MainApp.getDbHelper().getDaoDanaRHistory(); + QueryBuilder queryBuilder = dao.queryBuilder(); + queryBuilder.orderBy("recordDate", false); + Where where = queryBuilder.where(); + where.eq("recordCode", type); + queryBuilder.limit(10L); + PreparedQuery preparedQuery = queryBuilder.prepare(); + historyList = dao.query(preparedQuery); + } catch (SQLException e) { + e.printStackTrace(); + historyList = new ArrayList<>(); + } + runOnUiThread(new Runnable() { + @Override + public void run() { + cleanTable(tl); + cleanTable(ctl); + cleanTable(etl); + DateFormat df = new SimpleDateFormat("dd.MM."); + + if(TextUtils.isEmpty(TBB)) { + totalBaseBasal.setError("Please Enter Total Base Basal"); + return; + } + else { + magicNumber = Double.parseDouble(TBB); + } + + magicNumber *=2; + totalBaseBasal2.setText(decimalFormat.format(magicNumber)); + + int i = 0; + double sum = 0d; + double weighted03 = 0d; + double weighted05 = 0d; + double weighted07 = 0d; + + for (DanaRHistoryRecord record: historyList) { + double tdd= record.getRecordDailyBolus() + record.getRecordDailyBasal(); + + // Create the table row + TableRow tr = new TableRow(DanaRStatsActivity.this); + if(i%2!=0) tr.setBackgroundColor(Color.DKGRAY); + tr.setId(100+i); + tr.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // Here create the TextView dynamically + TextView labelDATE = new TextView(DanaRStatsActivity.this); + labelDATE.setId(200+i); + labelDATE.setText(df.format(new Date(record.getRecordDate()))); + labelDATE.setTextColor(Color.WHITE); + tr.addView(labelDATE); + + TextView labelBASAL = new TextView(DanaRStatsActivity.this); + labelBASAL.setId(300+i); + labelBASAL.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBasal()) + " U"); + labelBASAL.setTextColor(Color.WHITE); + tr.addView(labelBASAL); + + TextView labelBOLUS = new TextView(DanaRStatsActivity.this); + labelBOLUS.setId(400+i); + labelBOLUS.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBolus()) + " U"); + labelBOLUS.setTextColor(Color.WHITE); + tr.addView(labelBOLUS); + + TextView labelTDD = new TextView(DanaRStatsActivity.this); + labelTDD.setId(500+i); + labelTDD.setText(DecimalFormatter.to2Decimal(tdd) + " U"); + labelTDD.setTextColor(Color.WHITE); + tr.addView(labelTDD); + + TextView labelRATIO = new TextView(DanaRStatsActivity.this); + labelRATIO.setId(600+i); + labelRATIO.setText(Math.round(100*tdd/magicNumber) +" %"); + labelRATIO.setTextColor(Color.WHITE); + tr.addView(labelRATIO); + + // add stats rows to tables + tl.addView(tr, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + sum = sum + tdd; + i++; + + // Create the cumtable row + TableRow ctr = new TableRow(DanaRStatsActivity.this); + if(i%2==0) ctr.setBackgroundColor(Color.DKGRAY); + ctr.setId(700+i); + ctr.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // Here create the TextView dynamically + TextView labelDAYS = new TextView(DanaRStatsActivity.this); + labelDAYS.setId(800+i); + labelDAYS.setText("" + i); + labelDAYS.setTextColor(Color.WHITE); + ctr.addView(labelDAYS); + + TextView labelCUMTDD = new TextView(DanaRStatsActivity.this); + labelCUMTDD.setId(900+i); + labelCUMTDD.setText(DecimalFormatter.to2Decimal(sum/i) + " U"); + labelCUMTDD.setTextColor(Color.WHITE); + ctr.addView(labelCUMTDD); + + TextView labelCUMRATIO = new TextView(DanaRStatsActivity.this); + labelCUMRATIO.setId(1000+i); + labelCUMRATIO.setText(Math.round(100*sum/i/magicNumber) + " %"); + labelCUMRATIO.setTextColor(Color.WHITE); + ctr.addView(labelCUMRATIO); + + // add cummulative rows to tables + ctl.addView(ctr, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + } + + if (historyList.size()<3 || !(df.format(new Date(historyList.get(0).getRecordDate())).equals(df.format(new Date(System.currentTimeMillis() - 1000*60*60*24))))){ + statsMessage.setVisibility(View.VISIBLE); + statsMessage.setText(getString(R.string.danar_stats_olddata_Message)); + + } else { + tl.setBackgroundColor(Color.TRANSPARENT); + } + + Collections.reverse(historyList); + + i = 0; + + for (DanaRHistoryRecord record: historyList) { + double tdd= record.getRecordDailyBolus() + record.getRecordDailyBasal(); + if(i == 0 ) { + weighted03 = tdd; + weighted05 = tdd; + weighted07 = tdd; + + } else { + weighted07 = (weighted07*0.3 + tdd*0.7); + weighted05 = (weighted05*0.5 + tdd*0.5); + weighted03 = (weighted03*0.7 + tdd*0.3); + } + i++; + } + + // Create the exptable row + TableRow etr = new TableRow(DanaRStatsActivity.this); + if(i%2!=0) etr.setBackgroundColor(Color.DKGRAY); + etr.setId(1100+i); + etr.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // Here create the TextView dynamically + TextView labelWEIGHT = new TextView(DanaRStatsActivity.this); + labelWEIGHT.setId(1200+i); + labelWEIGHT.setText("0.3\n" + "0.5\n" + "0.7"); + labelWEIGHT.setTextColor(Color.WHITE); + etr.addView(labelWEIGHT); + + TextView labelEXPTDD = new TextView(DanaRStatsActivity.this); + labelEXPTDD.setId(1300+i); + labelEXPTDD.setText(DecimalFormatter.to2Decimal(weighted03) + + " U\n" + DecimalFormatter.to2Decimal(weighted05) + + " U\n" + DecimalFormatter.to2Decimal(weighted07) + " U"); + labelEXPTDD.setTextColor(Color.WHITE); + etr.addView(labelEXPTDD); + + TextView labelEXPRATIO = new TextView(DanaRStatsActivity.this); + labelEXPRATIO.setId(1400+i); + labelEXPRATIO.setText(Math.round(100*weighted03/magicNumber) +" %\n" + + Math.round(100*weighted05/magicNumber) +" %\n" + + Math.round(100*weighted07/magicNumber) +" %"); + labelEXPRATIO.setTextColor(Color.WHITE); + etr.addView(labelEXPRATIO); + + // add exponentail rows to tables + etl.addView(etr, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + } + }); + } + + private void cleanTable(TableLayout table) { + int childCount = table.getChildCount(); + // Remove all rows except the first one + if (childCount > 1) { + table.removeViews(1, childCount - 1); + } + } + + @Subscribe + public void onStatusEvent(final EventDanaRSyncStatus s) { + log.debug("EventDanaRSyncStatus: " + s.message); + runOnUiThread( + new Runnable() { + @Override + public void run() { + statusView.setText(s.message); + } + }); + } + + @Subscribe + public void onStatusEvent(final EventDanaRConnectionStatus c) { + runOnUiThread( + new Runnable() { + @Override + public void run() { + if (c.sStatus == EventDanaRConnectionStatus.CONNECTING) { + statusView.setText(String.format(getString(R.string.danar_history_connectingfor), c.sSecondsElapsed)); + log.debug("EventDanaRConnectionStatus: " + "Connecting for " + c.sSecondsElapsed + "s"); + } else if (c.sStatus == EventDanaRConnectionStatus.CONNECTED) { + statusView.setText(MainApp.sResources.getString(R.string.connected)); + log.debug("EventDanaRConnectionStatus: Connected"); + } else { + statusView.setText(MainApp.sResources.getString(R.string.disconnected)); + log.debug("EventDanaRConnectionStatus: Disconnected"); + } + } + } + ); + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanFragment.java index 907718f636..56ed323c17 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/DanaRKoreanFragment.java @@ -31,6 +31,7 @@ import info.nightscout.androidaps.plugins.DanaR.Dialogs.ProfileViewDialog; import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus; import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRNewStatus; import info.nightscout.androidaps.plugins.DanaRKorean.History.DanaRHistoryActivity; +import info.nightscout.androidaps.plugins.DanaRKorean.History.DanaRStatsActivity; import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.SetWarnColor; @@ -62,6 +63,8 @@ public class DanaRKoreanFragment extends Fragment implements FragmentBase { TextView iobView; Button viewProfileButton; Button historyButton; + Button statsButton; + public DanaRKoreanFragment() { if (sHandlerThread == null) { @@ -102,6 +105,8 @@ public class DanaRKoreanFragment extends Fragment implements FragmentBase { iobView = (TextView) view.findViewById(R.id.danar_iob); viewProfileButton = (Button) view.findViewById(R.id.danar_viewprofile); historyButton = (Button) view.findViewById(R.id.danar_history); + statsButton = (Button) view.findViewById(R.id.danar_stats); + viewProfileButton.setOnClickListener(new View.OnClickListener() { @Override @@ -119,6 +124,13 @@ public class DanaRKoreanFragment extends Fragment implements FragmentBase { } }); + statsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(getContext(), DanaRStatsActivity.class)); + } + }); + btConnectionView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/History/DanaRStatsActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/History/DanaRStatsActivity.java new file mode 100644 index 0000000000..bf7a7c4321 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/DanaRKorean/History/DanaRStatsActivity.java @@ -0,0 +1,570 @@ +package info.nightscout.androidaps.plugins.DanaRKorean.History; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.support.v7.widget.LinearLayoutManager; +import android.text.TextUtils; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.stmt.PreparedQuery; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.stmt.Where; +import com.squareup.otto.Subscribe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.SQLException; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.db.DanaRHistoryRecord; +import info.nightscout.androidaps.interfaces.ProfileInterface; +import info.nightscout.androidaps.plugins.CircadianPercentageProfile.CircadianPercentageProfilePlugin; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.DanaR.comm.RecordTypes; +import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRConnectionStatus; +import info.nightscout.androidaps.plugins.DanaR.events.EventDanaRSyncStatus; +import info.nightscout.androidaps.plugins.DanaRKorean.Services.ExecutionService; +import info.nightscout.utils.DecimalFormatter; +import info.nightscout.utils.ToastUtils; + +public class DanaRStatsActivity extends Activity { + private static Logger log = LoggerFactory.getLogger(DanaRStatsActivity.class); + + private boolean mBounded; + private static ExecutionService mExecutionService; + + private Handler mHandler; + private static HandlerThread mHandlerThread; + + TextView statusView, statsMessage,totalBaseBasal2; + EditText totalBaseBasal; + Button reloadButton; + LinearLayoutManager llm; + TableLayout tl,ctl,etl; + String TBB; + double magicNumber; + DecimalFormat decimalFormat; + + List historyList = new ArrayList<>(); + + public DanaRStatsActivity() { + super(); + mHandlerThread = new HandlerThread(DanaRStatsActivity.class.getSimpleName()); + mHandlerThread.start(); + this.mHandler = new Handler(mHandlerThread.getLooper()); + } + + @Override + public void onStart() { + super.onStart(); + Intent intent = new Intent(this, ExecutionService.class); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onResume() { + super.onResume(); + MainApp.bus().register(this); + } + + @Override + protected void onPause() { + super.onPause(); + MainApp.bus().unregister(this); + } + + @Override + public void onStop() { + super.onStop(); + if (mBounded) { + unbindService(mConnection); + mBounded = false; + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + View myView = getCurrentFocus(); + if ( myView instanceof EditText) { + Rect rect = new Rect(); + myView.getGlobalVisibleRect(rect); + if (!rect.contains((int)event.getRawX(), (int)event.getRawY())) { + myView.clearFocus(); + } + } + } + return super.dispatchTouchEvent( event ); + } + + ServiceConnection mConnection = new ServiceConnection() { + + public void onServiceDisconnected(ComponentName name) { + log.debug("Service is disconnected"); + mBounded = false; + mExecutionService = null; + } + + public void onServiceConnected(ComponentName name, IBinder service) { + log.debug("Service is connected"); + mBounded = true; + ExecutionService.LocalBinder mLocalBinder = (ExecutionService.LocalBinder) service; + mExecutionService = mLocalBinder.getServiceInstance(); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.danar_statsactivity); + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + statusView = (TextView) findViewById(R.id.danar_stats_connection_status); + reloadButton = (Button) findViewById(R.id.danar_statsreload); + totalBaseBasal = (EditText) findViewById(R.id.danar_stats_editTotalBaseBasal); + totalBaseBasal2 = (TextView) findViewById(R.id.danar_stats_editTotalBaseBasal2); + statsMessage = (TextView) findViewById(R.id.danar_stats_Message); + + statusView.setVisibility(View.GONE); + statsMessage.setVisibility(View.GONE); + + totalBaseBasal2.setEnabled(false); + totalBaseBasal2.setClickable(false); + totalBaseBasal2.setFocusable(false); + totalBaseBasal2.setInputType(0); + + decimalFormat = new DecimalFormat("0.000"); + llm = new LinearLayoutManager(this); + + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + TBB = preferences.getString("TBB", "10.00"); + totalBaseBasal.setText(TBB); + + ProfileInterface pi = ConfigBuilderPlugin.getActiveProfile(); + if (pi != null && pi instanceof CircadianPercentageProfilePlugin){ + double cppTBB = ((CircadianPercentageProfilePlugin)pi).baseBasalSum(); + totalBaseBasal.setText(decimalFormat.format(cppTBB)); + SharedPreferences.Editor edit = preferences.edit(); + edit.putString("TBB",totalBaseBasal.getText().toString()); + edit.commit(); + TBB = preferences.getString("TBB", ""); + } + + // stats table + tl = (TableLayout) findViewById(R.id.main_table); + TableRow tr_head = new TableRow(this); + tr_head.setBackgroundColor(Color.DKGRAY); + tr_head.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + TextView label_date = new TextView(this); + label_date.setText(getString(R.string.danar_stats_date)); + label_date.setTextColor(Color.WHITE); + tr_head.addView(label_date); + + TextView label_basalrate = new TextView(this); + label_basalrate.setText(getString(R.string.danar_stats_basalrate)); + label_basalrate.setTextColor(Color.WHITE); + tr_head.addView(label_basalrate); + + TextView label_bolus = new TextView(this); + label_bolus.setText(getString(R.string.danar_stats_bolus)); + label_bolus.setTextColor(Color.WHITE); + tr_head.addView(label_bolus); + + TextView label_tdd = new TextView(this); + label_tdd.setText(getString(R.string.danar_stats_tdd)); + label_tdd.setTextColor(Color.WHITE); + tr_head.addView(label_tdd); + + TextView label_ratio = new TextView(this); + label_ratio.setText(getString(R.string.danar_stats_ratio)); + label_ratio.setTextColor(Color.WHITE); + tr_head.addView(label_ratio); + + // add stats headers to tables + tl.addView(tr_head, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // cumulative table + ctl = (TableLayout) findViewById(R.id.cumulative_table); + TableRow ctr_head = new TableRow(this); + ctr_head.setBackgroundColor(Color.DKGRAY); + ctr_head.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + TextView label_cum_amount_days = new TextView(this); + label_cum_amount_days.setText(getString(R.string.danar_stats_amount_days)); + label_cum_amount_days.setTextColor(Color.WHITE); + ctr_head.addView(label_cum_amount_days); + + TextView label_cum_tdd = new TextView(this); + label_cum_tdd.setText(getString(R.string.danar_stats_tdd)); + label_cum_tdd.setTextColor(Color.WHITE); + ctr_head.addView(label_cum_tdd); + + TextView label_cum_ratio = new TextView(this); + label_cum_ratio.setText(getString(R.string.danar_stats_ratio)); + label_cum_ratio.setTextColor(Color.WHITE); + ctr_head.addView(label_cum_ratio); + + // add cummulative headers to tables + ctl.addView(ctr_head, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // expontial table + etl = (TableLayout) findViewById(R.id.expweight_table); + TableRow etr_head = new TableRow(this); + etr_head.setBackgroundColor(Color.DKGRAY); + etr_head.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + TextView label_exp_weight = new TextView(this); + label_exp_weight.setText(getString(R.string.danar_stats_weight)); + label_exp_weight.setTextColor(Color.WHITE); + etr_head.addView(label_exp_weight); + + TextView label_exp_tdd = new TextView(this); + label_exp_tdd.setText(getString(R.string.danar_stats_tdd)); + label_exp_tdd.setTextColor(Color.WHITE); + etr_head.addView(label_exp_tdd); + + TextView label_exp_ratio = new TextView(this); + label_exp_ratio.setText(getString(R.string.danar_stats_ratio)); + label_exp_ratio.setTextColor(Color.WHITE); + etr_head.addView(label_exp_ratio); + + // add expontial headers to tables + etl.addView(etr_head, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + reloadButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mExecutionService.isConnected() || mExecutionService.isConnecting()) { + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.pumpbusy)); + return; + } + mHandler.post(new Runnable() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + reloadButton.setVisibility(View.GONE); + statusView.setVisibility(View.VISIBLE); + statsMessage.setVisibility(View.VISIBLE); + statsMessage.setText(getString(R.string.danar_stats_warning_Message)); + } + }); + mExecutionService.loadHistory(RecordTypes.RECORD_TYPE_DAILY); + loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); + runOnUiThread(new Runnable() { + @Override + public void run() { + reloadButton.setVisibility(View.VISIBLE); + statusView.setVisibility(View.GONE); + statsMessage.setVisibility(View.GONE); + } + }); + } + }); + } + }); + + totalBaseBasal.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if(actionId== EditorInfo.IME_ACTION_DONE){ + totalBaseBasal.clearFocus(); + return true; + } + return false; + } + }); + + totalBaseBasal.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if(hasFocus){ + totalBaseBasal.getText().clear(); + } else { + SharedPreferences.Editor edit = preferences.edit(); + edit.putString("TBB",totalBaseBasal.getText().toString()); + edit.commit(); + TBB = preferences.getString("TBB", ""); + loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); + InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(totalBaseBasal.getWindowToken(), 0); + } + } + }); + + loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); + } + + private void loadDataFromDB(byte type) { + try { + Dao dao = MainApp.getDbHelper().getDaoDanaRHistory(); + QueryBuilder queryBuilder = dao.queryBuilder(); + queryBuilder.orderBy("recordDate", false); + Where where = queryBuilder.where(); + where.eq("recordCode", type); + queryBuilder.limit(10L); + PreparedQuery preparedQuery = queryBuilder.prepare(); + historyList = dao.query(preparedQuery); + } catch (SQLException e) { + e.printStackTrace(); + historyList = new ArrayList<>(); + } + runOnUiThread(new Runnable() { + @Override + public void run() { + cleanTable(tl); + cleanTable(ctl); + cleanTable(etl); + DateFormat df = new SimpleDateFormat("dd.MM."); + + if(TextUtils.isEmpty(TBB)) { + totalBaseBasal.setError("Please Enter Total Base Basal"); + return; + } + else { + magicNumber = Double.parseDouble(TBB); + } + + magicNumber *=2; + totalBaseBasal2.setText(decimalFormat.format(magicNumber)); + + int i = 0; + double sum = 0d; + double weighted03 = 0d; + double weighted05 = 0d; + double weighted07 = 0d; + + for (DanaRHistoryRecord record: historyList) { + double tdd= record.getRecordDailyBolus() + record.getRecordDailyBasal(); + + // Create the table row + TableRow tr = new TableRow(DanaRStatsActivity.this); + if(i%2!=0) tr.setBackgroundColor(Color.DKGRAY); + tr.setId(100+i); + tr.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // Here create the TextView dynamically + TextView labelDATE = new TextView(DanaRStatsActivity.this); + labelDATE.setId(200+i); + labelDATE.setText(df.format(new Date(record.getRecordDate()))); + labelDATE.setTextColor(Color.WHITE); + tr.addView(labelDATE); + + TextView labelBASAL = new TextView(DanaRStatsActivity.this); + labelBASAL.setId(300+i); + labelBASAL.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBasal()) + " U"); + labelBASAL.setTextColor(Color.WHITE); + tr.addView(labelBASAL); + + TextView labelBOLUS = new TextView(DanaRStatsActivity.this); + labelBOLUS.setId(400+i); + labelBOLUS.setText(DecimalFormatter.to2Decimal(record.getRecordDailyBolus()) + " U"); + labelBOLUS.setTextColor(Color.WHITE); + tr.addView(labelBOLUS); + + TextView labelTDD = new TextView(DanaRStatsActivity.this); + labelTDD.setId(500+i); + labelTDD.setText(DecimalFormatter.to2Decimal(tdd) + " U"); + labelTDD.setTextColor(Color.WHITE); + tr.addView(labelTDD); + + TextView labelRATIO = new TextView(DanaRStatsActivity.this); + labelRATIO.setId(600+i); + labelRATIO.setText(Math.round(100*tdd/magicNumber) +" %"); + labelRATIO.setTextColor(Color.WHITE); + tr.addView(labelRATIO); + + // add stats rows to tables + tl.addView(tr, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + sum = sum + tdd; + i++; + + // Create the cumtable row + TableRow ctr = new TableRow(DanaRStatsActivity.this); + if(i%2==0) ctr.setBackgroundColor(Color.DKGRAY); + ctr.setId(700+i); + ctr.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // Here create the TextView dynamically + TextView labelDAYS = new TextView(DanaRStatsActivity.this); + labelDAYS.setId(800+i); + labelDAYS.setText("" + i); + labelDAYS.setTextColor(Color.WHITE); + ctr.addView(labelDAYS); + + TextView labelCUMTDD = new TextView(DanaRStatsActivity.this); + labelCUMTDD.setId(900+i); + labelCUMTDD.setText(DecimalFormatter.to2Decimal(sum/i) + " U"); + labelCUMTDD.setTextColor(Color.WHITE); + ctr.addView(labelCUMTDD); + + TextView labelCUMRATIO = new TextView(DanaRStatsActivity.this); + labelCUMRATIO.setId(1000+i); + labelCUMRATIO.setText(Math.round(100*sum/i/magicNumber) + " %"); + labelCUMRATIO.setTextColor(Color.WHITE); + ctr.addView(labelCUMRATIO); + + // add cummulative rows to tables + ctl.addView(ctr, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + } + + if (historyList.size()<3 || !(df.format(new Date(historyList.get(0).getRecordDate())).equals(df.format(new Date(System.currentTimeMillis() - 1000*60*60*24))))){ + statsMessage.setVisibility(View.VISIBLE); + statsMessage.setText(getString(R.string.danar_stats_olddata_Message)); + + } else { + tl.setBackgroundColor(Color.TRANSPARENT); + } + + Collections.reverse(historyList); + + i = 0; + + for (DanaRHistoryRecord record: historyList) { + double tdd= record.getRecordDailyBolus() + record.getRecordDailyBasal(); + if(i == 0 ) { + weighted03 = tdd; + weighted05 = tdd; + weighted07 = tdd; + + } else { + weighted07 = (weighted07*0.3 + tdd*0.7); + weighted05 = (weighted05*0.5 + tdd*0.5); + weighted03 = (weighted03*0.7 + tdd*0.3); + } + i++; + } + + // Create the exptable row + TableRow etr = new TableRow(DanaRStatsActivity.this); + if(i%2!=0) etr.setBackgroundColor(Color.DKGRAY); + etr.setId(1100+i); + etr.setLayoutParams(new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + + // Here create the TextView dynamically + TextView labelWEIGHT = new TextView(DanaRStatsActivity.this); + labelWEIGHT.setId(1200+i); + labelWEIGHT.setText("0.3\n" + "0.5\n" + "0.7"); + labelWEIGHT.setTextColor(Color.WHITE); + etr.addView(labelWEIGHT); + + TextView labelEXPTDD = new TextView(DanaRStatsActivity.this); + labelEXPTDD.setId(1300+i); + labelEXPTDD.setText(DecimalFormatter.to2Decimal(weighted03) + + " U\n" + DecimalFormatter.to2Decimal(weighted05) + + " U\n" + DecimalFormatter.to2Decimal(weighted07) + " U"); + labelEXPTDD.setTextColor(Color.WHITE); + etr.addView(labelEXPTDD); + + TextView labelEXPRATIO = new TextView(DanaRStatsActivity.this); + labelEXPRATIO.setId(1400+i); + labelEXPRATIO.setText(Math.round(100*weighted03/magicNumber) +" %\n" + + Math.round(100*weighted05/magicNumber) +" %\n" + + Math.round(100*weighted07/magicNumber) +" %"); + labelEXPRATIO.setTextColor(Color.WHITE); + etr.addView(labelEXPRATIO); + + // add exponentail rows to tables + etl.addView(etr, new TableLayout.LayoutParams( + TableLayout.LayoutParams.FILL_PARENT, + TableLayout.LayoutParams.WRAP_CONTENT)); + } + }); + } + + private void cleanTable(TableLayout table) { + int childCount = table.getChildCount(); + // Remove all rows except the first one + if (childCount > 1) { + table.removeViews(1, childCount - 1); + } + } + + @Subscribe + public void onStatusEvent(final EventDanaRSyncStatus s) { + log.debug("EventDanaRSyncStatus: " + s.message); + runOnUiThread( + new Runnable() { + @Override + public void run() { + statusView.setText(s.message); + } + }); + } + + @Subscribe + public void onStatusEvent(final EventDanaRConnectionStatus c) { + runOnUiThread( + new Runnable() { + @Override + public void run() { + if (c.sStatus == EventDanaRConnectionStatus.CONNECTING) { + statusView.setText(String.format(getString(R.string.danar_history_connectingfor), c.sSecondsElapsed)); + log.debug("EventDanaRConnectionStatus: " + "Connecting for " + c.sSecondsElapsed + "s"); + } else if (c.sStatus == EventDanaRConnectionStatus.CONNECTED) { + statusView.setText(MainApp.sResources.getString(R.string.connected)); + log.debug("EventDanaRConnectionStatus: Connected"); + } else { + statusView.setText(MainApp.sResources.getString(R.string.disconnected)); + log.debug("EventDanaRConnectionStatus: Disconnected"); + } + } + } + ); + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java index f605b5362c..7f4d1c4aa9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/Autosens.java @@ -76,7 +76,7 @@ public class Autosens { double[] bgis = new double[bucketed_data.size() - 2]; double[] deviations = new double[bucketed_data.size() - 2]; - String debugString = ""; + String pastSensitivity = ""; for (int i = 0; i < bucketed_data.size() - 3; ++i) { long bgTime = bucketed_data.get(i).timeIndex; int secondsFromMidnight = NSProfile.secondsFromMidnight(new Date(bgTime)); @@ -108,20 +108,21 @@ public class Autosens { // Exclude large positive deviations (carb absorption) from autosens if (avgDelta - bgi < 6) { if (deviation > 0) { - debugString += "+"; + pastSensitivity += "+"; } else if (deviation == 0) { - debugString += "="; + pastSensitivity += "="; } else { - debugString += "-"; + pastSensitivity += "-"; } avgDeltas[i] = avgDelta; bgis[i] = bgi; deviations[i] = deviation; deviationSum += deviation; } else { - debugString += ">"; + pastSensitivity += ">"; //console.error(bgTime); } + //log.debug("TIME: " + new Date(bgTime).toString() + " BG: " + bg + " SENS: " + sens + " DELTA: " + delta + " AVGDELTA: " + avgDelta + " IOB: " + iob.iob + " ACTIVITY: " + iob.activity + " BGI: " + bgi + " DEVIATION: " + deviation); // if bgTime is more recent than mealTime if (bgTime > mealTime) { @@ -134,7 +135,7 @@ public class Autosens { } } //console.error(""); - log.debug(debugString); + log.debug(pastSensitivity); //console.log(JSON.stringify(avgDeltas)); //console.log(JSON.stringify(bgis)); Arrays.sort(avgDeltas); @@ -157,15 +158,17 @@ public class Autosens { //console.error("Mean deviation: "+average.toFixed(2)); double basalOff = 0; + String sensResult = ""; if (pSensitive < 0) { // sensitive basalOff = pSensitive * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()); - log.debug("Excess insulin sensitivity detected: "); + sensResult = "Excess insulin sensitivity detected"; } else if (pResistant > 0) { // resistant basalOff = pResistant * (60 / 5) / NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()); - log.debug("Excess insulin resistance detected: "); + sensResult = "Excess insulin resistance detected"; } else { - log.debug("Sensitivity normal."); + sensResult = "Sensitivity normal"; } + log.debug(sensResult); double ratio = 1 + (basalOff / profile.getMaxDailyBasal()); // don't adjust more than 1.5x @@ -173,8 +176,10 @@ public class Autosens { ratio = Math.max(ratio, Constants.AUTOSENS_MIN); ratio = Math.min(ratio, Constants.AUTOSENS_MAX); + String ratioLimit = ""; if (ratio != rawRatio) { - log.debug("Ratio limited from " + rawRatio + " to " + ratio); + ratioLimit = "Ratio limited from " + rawRatio + " to " + ratio; + log.debug(ratioLimit); } double newisf = Math.round(NSProfile.toMgdl(profile.getIsf(NSProfile.secondsFromMidnight()), profile.getUnits()) / ratio); @@ -187,6 +192,9 @@ public class Autosens { AutosensResult output = new AutosensResult(); output.ratio = Round.roundTo(ratio, 0.01); output.carbsAbsorbed = Round.roundTo(carbsAbsorbed, 0.01); + output.pastSensitivity = pastSensitivity; + output.ratioLimit = ratioLimit; + output.sensResult = sensResult; return output; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/AutosensResult.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/AutosensResult.java index eec3bca2af..c42d7096f5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/AutosensResult.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/AutosensResult.java @@ -1,9 +1,30 @@ package info.nightscout.androidaps.plugins.OpenAPSAMA; +import org.json.JSONException; +import org.json.JSONObject; + /** * Created by mike on 06.01.2017. */ public class AutosensResult { public double ratio; public double carbsAbsorbed; + public String sensResult; + public String pastSensitivity; + public String ratioLimit; + + public JSONObject json() { + JSONObject ret = new JSONObject(); + try { + ret.put("ratio", ratio); + ret.put("ratioLimit", ratioLimit); + ret.put("pastSensitivity", pastSensitivity); + ret.put("sensResult", sensResult); + ret.put("ratio", ratio); + } catch (JSONException e) { + e.printStackTrace(); + } + return ret; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAFragment.java index ced20ffd49..4a8ce51266 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAFragment.java @@ -125,12 +125,14 @@ public class OpenAPSAMAFragment extends Fragment implements View.OnClickListener } profileView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getProfileParam())); mealDataView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getMealDataParam())); - autosensDataView.setText(JSONFormatter.format(determineBasalAdapterAMAJS.getAutosensDataParam())); scriptdebugView.setText(determineBasalAdapterAMAJS.getScriptDebug()); } if (getPlugin().lastAPSRun != null) { lastRunView.setText(getPlugin().lastAPSRun.toLocaleString()); } + if (getPlugin().lastAutosensResult != null) { + autosensDataView.setText(JSONFormatter.format(getPlugin().lastAutosensResult.json())); + } } }); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java index 457c70d7c1..9ba9dd48f8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java @@ -45,6 +45,7 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { DetermineBasalAdapterAMAJS lastDetermineBasalAdapterAMAJS = null; Date lastAPSRun = null; DetermineBasalResultAMA lastAPSResult = null; + AutosensResult lastAutosensResult = null; boolean fragmentEnabled = false; boolean fragmentVisible = true; @@ -146,13 +147,13 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); String units = profile.getUnits(); - String maxBgDefault = "180"; - String minBgDefault = "100"; - String targetBgDefault = "150"; + String maxBgDefault = Constants.MAX_BG_DEFAULT_MGDL; + String minBgDefault = Constants.MIN_BG_DEFAULT_MGDL; + String targetBgDefault = Constants.TARGET_BG_DEFAULT_MGDL; if (!units.equals(Constants.MGDL)) { - maxBgDefault = "10"; - minBgDefault = "5"; - targetBgDefault = "7"; + maxBgDefault = Constants.MAX_BG_DEFAULT_MMOL; + minBgDefault = Constants.MIN_BG_DEFAULT_MMOL; + targetBgDefault = Constants.TARGET_BG_DEFAULT_MMOL; } Date now = new Date(); @@ -172,9 +173,9 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob); - minBg = verifyHardLimits(minBg, "minBg", 72, 180); - maxBg = verifyHardLimits(maxBg, "maxBg", 100, 270); - targetBg = verifyHardLimits(targetBg, "targetBg", 80, 200); + minBg = verifyHardLimits(minBg, "minBg", Constants.VERY_HARD_LIMIT_MIN_BG[0], Constants.VERY_HARD_LIMIT_MIN_BG[1]); + maxBg = verifyHardLimits(maxBg, "maxBg", Constants.VERY_HARD_LIMIT_MAX_BG[0], Constants.VERY_HARD_LIMIT_MAX_BG[1]); + targetBg = verifyHardLimits(targetBg, "targetBg", Constants.VERY_HARD_LIMIT_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TARGET_BG[1]); boolean isTempTarget = false; TempTargetRangePlugin tempTargetRangePlugin = (TempTargetRangePlugin) MainApp.getSpecificPlugin(TempTargetRangePlugin.class); @@ -182,9 +183,9 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { TempTarget tempTarget = tempTargetRangePlugin.getTempTargetInProgress(new Date().getTime()); if (tempTarget != null) { isTempTarget = true; - minBg = verifyHardLimits(tempTarget.low, "minBg", 72, 180); - maxBg = verifyHardLimits(tempTarget.high, "maxBg", 72, 270); - targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", 72, 200); + minBg = verifyHardLimits(tempTarget.low, "minBg", Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[1]); + maxBg = verifyHardLimits(tempTarget.high, "maxBg", Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[1]); + targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]); } } @@ -202,10 +203,10 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { long oldestDataAvailable = MainApp.getConfigBuilder().getActiveTempBasals().oldestDataAvaialable(); List bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(Math.max(oldestDataAvailable, (long) (new Date().getTime() - 60 * 60 * 1000L * (24 + profile.getDia()))), false); log.debug("Limiting data to oldest available temps: " + new Date(oldestDataAvailable).toString() + " (" + bgReadings.size() + " records)"); - AutosensResult autosensResult = Autosens.detectSensitivityandCarbAbsorption(bgReadings, new Date().getTime()); + lastAutosensResult = Autosens.detectSensitivityandCarbAbsorption(bgReadings, new Date().getTime()); determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobArray, glucoseStatus, mealData, - autosensResult.ratio, //autosensDataRatio + lastAutosensResult.ratio, //autosensDataRatio isTempTarget, Constants.MIN_5M_CARBIMPACT //min_5m_carbimpact ); @@ -247,15 +248,18 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { } public static Double verifyHardLimits(Double value, String valueName, double lowLimit, double highLimit) { - if (value < lowLimit || value > highLimit) { + Double newvalue = value; + if (newvalue < lowLimit || newvalue > highLimit) { + newvalue = Math.max(newvalue, lowLimit); + newvalue = Math.min(newvalue, highLimit); String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), valueName); + msg += ".\n"; + msg += String.format(MainApp.sResources.getString(R.string.openapsma_valuelimitedto), value, newvalue); log.error(msg); MainApp.getConfigBuilder().uploadError(msg); ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error); - value = Math.max(value, lowLimit); - value = Math.min(value, highLimit); } - return value; + return newvalue; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java index d3882450a9..f6c7be26e2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java @@ -34,6 +34,9 @@ import info.nightscout.utils.Round; import info.nightscout.utils.SafeParse; import info.nightscout.utils.ToastUtils; +import static info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin.checkOnlyHardLimits; +import static info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin.verifyHardLimits; + /** * Created by mike on 05.08.2016. */ @@ -145,13 +148,13 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface { SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); String units = profile.getUnits(); - String maxBgDefault = "180"; - String minBgDefault = "100"; - String targetBgDefault = "150"; + String maxBgDefault = Constants.MAX_BG_DEFAULT_MGDL; + String minBgDefault = Constants.MIN_BG_DEFAULT_MGDL; + String targetBgDefault = Constants.TARGET_BG_DEFAULT_MGDL; if (!units.equals(Constants.MGDL)) { - maxBgDefault = "10"; - minBgDefault = "5"; - targetBgDefault = "7"; + maxBgDefault = Constants.MAX_BG_DEFAULT_MMOL; + minBgDefault = Constants.MIN_BG_DEFAULT_MMOL; + targetBgDefault = Constants.TARGET_BG_DEFAULT_MMOL; } Date now = new Date(); @@ -178,17 +181,17 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface { maxIob = MainApp.getConfigBuilder().applyMaxIOBConstraints(maxIob); - minBg = verifyHardLimits(minBg, "minBg", 72, 180); - maxBg = verifyHardLimits(maxBg, "maxBg", 100, 270); - targetBg = verifyHardLimits(targetBg, "targetBg", 80, 200); - + minBg = verifyHardLimits(minBg, "minBg", Constants.VERY_HARD_LIMIT_MIN_BG[0], Constants.VERY_HARD_LIMIT_MIN_BG[1]); + maxBg = verifyHardLimits(maxBg, "maxBg", Constants.VERY_HARD_LIMIT_MAX_BG[0], Constants.VERY_HARD_LIMIT_MAX_BG[1]); + targetBg = verifyHardLimits(targetBg, "targetBg", Constants.VERY_HARD_LIMIT_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TARGET_BG[1]); + TempTargetRangePlugin tempTargetRangePlugin = (TempTargetRangePlugin) MainApp.getSpecificPlugin(TempTargetRangePlugin.class); if (tempTargetRangePlugin != null && tempTargetRangePlugin.isEnabled(PluginBase.GENERAL)) { TempTarget tempTarget = tempTargetRangePlugin.getTempTargetInProgress(new Date().getTime()); if (tempTarget != null) { - minBg = verifyHardLimits(tempTarget.low, "minBg", 72, 180); - maxBg = verifyHardLimits(tempTarget.high, "maxBg", 72, 270); - targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", 72, 200); + minBg = verifyHardLimits(tempTarget.low, "minBg", Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MIN_BG[1]); + maxBg = verifyHardLimits(tempTarget.high, "maxBg", Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[0], Constants.VERY_HARD_LIMIT_TEMP_MAX_BG[1]); + targetBg = verifyHardLimits((tempTarget.low + tempTarget.high) / 2, "targetBg", Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[0], Constants.VERY_HARD_LIMIT_TEMP_TARGET_BG[1]); } } @@ -235,21 +238,5 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface { //deviceStatus.suggested = determineBasalResultMA.json; } - // safety checks - public static boolean checkOnlyHardLimits(Double value, String valueName, double lowLimit, double highLimit) { - return value.equals(verifyHardLimits(value, valueName, lowLimit, highLimit)); - } - - public static Double verifyHardLimits(Double value, String valueName, double lowLimit, double highLimit) { - if (value < lowLimit || value > highLimit) { - String msg = String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), valueName); - log.error(msg); - MainApp.getConfigBuilder().uploadError(msg); - ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), msg, R.raw.error); - value = Math.max(value, lowLimit); - value = Math.min(value, highLimit); - } - return value; - } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java index 709037362b..763c6acc80 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java @@ -83,6 +83,7 @@ import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLab import info.nightscout.androidaps.plugins.Overview.graphExtensions.TimeAsXAxisLabelFormatter; import info.nightscout.androidaps.plugins.TempBasals.TempBasalsPlugin; import info.nightscout.androidaps.plugins.TempTargetRange.TempTargetRangePlugin; +import info.nightscout.androidaps.plugins.TempTargetRange.events.EventTempTargetRangeChange; import info.nightscout.client.data.NSProfile; import info.nightscout.utils.BolusWizard; import info.nightscout.utils.DateUtil; @@ -113,6 +114,7 @@ public class OverviewFragment extends Fragment { TextView iobView; TextView apsModeView; TextView tempTargetView; + TextView initializingView; GraphView bgGraph; CheckBox showPredictionView; @@ -121,7 +123,6 @@ public class OverviewFragment extends Fragment { LinearLayout cancelTempLayout; LinearLayout acceptTempLayout; - LinearLayout quickWizardLayout; Button cancelTempButton; Button treatmentButton; Button wizardButton; @@ -158,6 +159,7 @@ public class OverviewFragment extends Fragment { baseBasalView = (TextView) view.findViewById(R.id.overview_basebasal); basalLayout = (LinearLayout) view.findViewById(R.id.overview_basallayout); activeProfileView = (TextView) view.findViewById(R.id.overview_activeprofile); + initializingView = (TextView) view.findViewById(R.id.overview_initializing); iobView = (TextView) view.findViewById(R.id.overview_iob); apsModeView = (TextView) view.findViewById(R.id.overview_apsmode); @@ -171,7 +173,6 @@ public class OverviewFragment extends Fragment { acceptTempButton = (Button) view.findViewById(R.id.overview_accepttempbutton); acceptTempLayout = (LinearLayout) view.findViewById(R.id.overview_accepttemplayout); quickWizardButton = (Button) view.findViewById(R.id.overview_quickwizard); - quickWizardLayout = (LinearLayout) view.findViewById(R.id.overview_quickwizardlayout); showPredictionView = (CheckBox) view.findViewById(R.id.overview_showprediction); notificationsView = (RecyclerView) view.findViewById(R.id.overview_notifications); @@ -285,7 +286,7 @@ public class OverviewFragment extends Fragment { QuickWizard.QuickWizardEntry quickWizardEntry = getPlugin().quickWizard.getActive(); if (quickWizardEntry != null && lastBG != null) { - quickWizardLayout.setVisibility(View.VISIBLE); + quickWizardButton.setVisibility(View.VISIBLE); String text = MainApp.sResources.getString(R.string.bolus) + ": " + quickWizardEntry.buttonText(); BolusWizard wizard = new BolusWizard(); wizard.doCalc(profile.getDefaultProfile(), quickWizardEntry.carbs(), lastBG.valueToUnits(profile.getUnits()), 0d, true, true); @@ -431,6 +432,9 @@ public class OverviewFragment extends Fragment { @Subscribe public void onStatusEvent(final EventNewBasalProfile ev) { updateGUIIfVisible(); } + @Subscribe + public void onStatusEvent(final EventTempTargetRangeChange ev) {updateGUIIfVisible();} + @Subscribe public void onStatusEvent(final EventNewNotification n) { updateNotifications(); } @@ -464,8 +468,14 @@ public class OverviewFragment extends Fragment { updateNotifications(); BgReading actualBG = MainApp.getDbHelper().actualBg(); BgReading lastBG = MainApp.getDbHelper().lastBg(); - if (MainApp.getConfigBuilder() == null || MainApp.getConfigBuilder().getActiveProfile() == null || MainApp.getConfigBuilder().getActiveProfile().getProfile() == null) // app not initialized yet + + if (MainApp.getConfigBuilder() == null || MainApp.getConfigBuilder().getActiveProfile() == null || MainApp.getConfigBuilder().getActiveProfile().getProfile() == null) {// app not initialized yet + initializingView.setText(R.string.noprofileset); + initializingView.setVisibility(View.VISIBLE); return; + } else { + initializingView.setVisibility(View.GONE); + } // Skip if not initialized yet if (bgGraph == null) @@ -526,11 +536,25 @@ public class OverviewFragment extends Fragment { if (tempTargetRangePlugin != null && tempTargetRangePlugin.isEnabled(PluginBase.GENERAL)) { TempTarget tempTarget = tempTargetRangePlugin.getTempTargetInProgress(new Date().getTime()); if (tempTarget != null) { + tempTargetView.setTextColor(Color.BLACK); + tempTargetView.setBackgroundResource(R.drawable.temptargetborder); tempTargetView.setVisibility(View.VISIBLE); tempTargetView.setText(NSProfile.toUnitsString(tempTarget.low, NSProfile.fromMgdlToUnits(tempTarget.low, profile.getUnits()), profile.getUnits()) + " - " + NSProfile.toUnitsString(tempTarget.high, NSProfile.fromMgdlToUnits(tempTarget.high, profile.getUnits()), profile.getUnits())); } else { - tempTargetView.setVisibility(View.GONE); + + String maxBgDefault = Constants.MAX_BG_DEFAULT_MGDL; + String minBgDefault = Constants.MIN_BG_DEFAULT_MGDL; + if (!profile.getUnits().equals(Constants.MGDL)) { + maxBgDefault = Constants.MAX_BG_DEFAULT_MMOL; + minBgDefault = Constants.MIN_BG_DEFAULT_MMOL; + } + tempTargetView.setTextColor(Color.WHITE); + tempTargetView.setBackgroundResource(R.drawable.temptargetborderdisabled); + tempTargetView.setText(prefs.getString("openapsma_min_bg", minBgDefault) + " - " + prefs.getString("openapsma_max_bg", maxBgDefault)); + tempTargetView.setVisibility(View.VISIBLE); } + } else { + tempTargetView.setVisibility(View.GONE); } // **** Temp button **** @@ -583,34 +607,39 @@ public class OverviewFragment extends Fragment { }); activeProfileView.setLongClickable(true); - if (profile == null || !pump.isInitialized()) { - // disable all treatment buttons because we are not able to check constraints without profile - wizardButton.setVisibility(View.INVISIBLE); - treatmentButton.setVisibility(View.INVISIBLE); - return; - } else { - wizardButton.setVisibility(View.VISIBLE); - treatmentButton.setVisibility(View.VISIBLE); - } - String units = profile.getUnits(); + tempTargetView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + NewNSTreatmentDialog newTTDialog = new NewNSTreatmentDialog(); + final OptionsToShow temptarget = new OptionsToShow(R.id.careportal_temptarget, R.string.careportal_temptarget, false, false, false, false, true, false, false, false, false, true); + temptarget.executeTempTarget = true; + newTTDialog.setOptions(temptarget); + newTTDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); + return true; + } + }); + tempTargetView.setLongClickable(true); // QuickWizard button QuickWizard.QuickWizardEntry quickWizardEntry = getPlugin().quickWizard.getActive(); if (quickWizardEntry != null && lastBG != null && pump.isInitialized()) { - quickWizardLayout.setVisibility(View.VISIBLE); + quickWizardButton.setVisibility(View.VISIBLE); String text = MainApp.sResources.getString(R.string.bolus) + ": " + quickWizardEntry.buttonText() + " " + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g"; BolusWizard wizard = new BolusWizard(); wizard.doCalc(profile.getDefaultProfile(), quickWizardEntry.carbs(), lastBG.valueToUnits(profile.getUnits()), 0d, true, true); text += " " + DecimalFormatter.to2Decimal(wizard.calculatedTotalInsulin) + "U"; quickWizardButton.setText(text); if (wizard.calculatedTotalInsulin <= 0) - quickWizardLayout.setVisibility(View.GONE); + quickWizardButton.setVisibility(View.GONE); } else - quickWizardLayout.setVisibility(View.GONE); + quickWizardButton.setVisibility(View.GONE); + + String units = profile.getUnits(); // **** BG value **** - if (lastBG != null && bgView != null) { + if (lastBG != null) { bgView.setText(lastBG.valueToUnitsToString(profile.getUnits())); arrowView.setText(lastBG.directionToSymbol()); GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); @@ -885,6 +914,21 @@ public class OverviewFragment extends Fragment { bgGraph.getSecondScale().setMaxY(maxBgValue / lowLine * maxBasalValueFound * 1.2d); bgGraph.getGridLabelRenderer().setVerticalLabelsSecondScaleColor(MainApp.instance().getResources().getColor(R.color.background_material_dark)); // same color as backround = hide } + + // Pump not initialized message + if (!pump.isInitialized()) { + // disable all treatment buttons because we are not able to check constraints without profile + wizardButton.setVisibility(View.INVISIBLE); + treatmentButton.setVisibility(View.INVISIBLE); + quickWizardButton.setVisibility(View.INVISIBLE); + initializingView.setText(R.string.waitingforpump); + initializingView.setVisibility(View.VISIBLE); + } else { + wizardButton.setVisibility(View.VISIBLE); + treatmentButton.setVisibility(View.VISIBLE); + initializingView.setVisibility(View.GONE); + } + } //Notifications diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java index e79e07c816..9565f0ca6a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/TempBasals/TempBasalsPlugin.java @@ -180,6 +180,7 @@ public class TempBasalsPlugin implements PluginBase, TempBasalsInterface { if (useExtendedBoluses) { for (Integer pos = 0; pos < extendedBoluses.size(); pos++) { TempBasal t = extendedBoluses.get(pos); + if (t.timeStart.getTime() > time) continue; IobTotal calc = t.iobCalc(now); total.plus(calc); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangeFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangeFragment.java index 332da1d8bd..6693bbd717 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangeFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangeFragment.java @@ -83,10 +83,16 @@ public class TempTargetRangeFragment extends Fragment implements View.OnClickLis holder.reason.setText(tempTarget.reason); if (tempTarget.isInProgress()) holder.dateLinearLayout.setBackgroundColor(MainApp.instance().getResources().getColor(R.color.colorInProgress)); + else if (tempTarget.duration == 0){ + holder.low.setText(""); + holder.high.setText(""); + holder.duration.setText(R.string.cancel); + holder.dateLinearLayout.setBackgroundColor(MainApp.instance().getResources().getColor(R.color.notificationUrgent)); + } else holder.dateLinearLayout.setBackgroundColor(MainApp.instance().getResources().getColor(R.color.cardColorBackground)); holder.remove.setTag(tempTarget); - } + } @Override public int getItemCount() { @@ -98,7 +104,7 @@ public class TempTargetRangeFragment extends Fragment implements View.OnClickLis super.onAttachedToRecyclerView(recyclerView); } - public class TempTargetsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + public class TempTargetsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { CardView cv; TextView date; TextView duration; @@ -128,26 +134,26 @@ public class TempTargetRangeFragment extends Fragment implements View.OnClickLis final Context finalContext = context; switch (v.getId()) { case R.id.temptargetrange_remove: - final String _id = tempTarget._id; - if (_id != null && !_id.equals("")) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(MainApp.sResources.getString(R.string.confirmation)); - builder.setMessage(MainApp.sResources.getString(R.string.removerecord) + "\n" + _id); - builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(MainApp.sResources.getString(R.string.confirmation)); + builder.setMessage(MainApp.sResources.getString(R.string.removerecord) + "\n" + DateUtil.dateAndTimeString(tempTarget.timeStart)); + builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + final String _id = tempTarget._id; + if (_id != null && !_id.equals("")) { MainApp.getConfigBuilder().removeCareportalEntryFromNS(_id); - try { - Dao daoTempTargets = MainApp.getDbHelper().getDaoTempTargets(); - daoTempTargets.delete(tempTarget); - MainApp.bus().post(new EventTempTargetRangeChange()); - } catch (SQLException e) { - e.printStackTrace(); - } } - }); - builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null); - builder.show(); - } + try { + Dao daoTempTargets = MainApp.getDbHelper().getDaoTempTargets(); + daoTempTargets.delete(tempTarget); + MainApp.bus().post(new EventTempTargetRangeChange()); + } catch (SQLException e) { + e.printStackTrace(); + } + } + }); + builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null); + builder.show(); break; } } @@ -182,8 +188,8 @@ public class TempTargetRangeFragment extends Fragment implements View.OnClickLis case R.id.temptargetrange_refreshfromnightscout: SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getContext()); boolean nsUploadOnly = SP.getBoolean("ns_upload_only", false); - if(nsUploadOnly){ - ToastUtils.showToastInUiThread(getContext(),this.getContext().getString(R.string.ns_upload_only_enabled)); + if (nsUploadOnly) { + ToastUtils.showToastInUiThread(getContext(), this.getContext().getString(R.string.ns_upload_only_enabled)); } else { AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext()); builder.setTitle(this.getContext().getString(R.string.confirmation)); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangePlugin.java index 8b7068d94f..177ed8d9fe 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangePlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/TempTargetRange/TempTargetRangePlugin.java @@ -91,7 +91,10 @@ public class TempTargetRangePlugin implements PluginBase { @Nullable public TempTarget getTempTargetInProgress(long time) { - for (int i = tempTargets.size() - 1; i >= 0; i--) { + for (int i = 0; i < tempTargets.size(); i++) { + // a zero-duration temp target will cancel all prior targets + if (tempTargets.get(i).duration == 0) return null; + if (tempTargets.get(i).timeStart.getTime() > time) continue; if (tempTargets.get(i).getPlannedTimeEnd().getTime() >= time) return tempTargets.get(i); } diff --git a/app/src/main/res/drawable-mdpi-v11/temptargetborderdisabled.xml b/app/src/main/res/drawable-mdpi-v11/temptargetborderdisabled.xml new file mode 100644 index 0000000000..60a46f667e --- /dev/null +++ b/app/src/main/res/drawable-mdpi-v11/temptargetborderdisabled.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/initializingborder.xml b/app/src/main/res/drawable/initializingborder.xml new file mode 100644 index 0000000000..7a46a6f1eb --- /dev/null +++ b/app/src/main/res/drawable/initializingborder.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/actions_fragment.xml b/app/src/main/res/layout/actions_fragment.xml index 78b6fa00ae..7eb751ac1d 100644 --- a/app/src/main/res/layout/actions_fragment.xml +++ b/app/src/main/res/layout/actions_fragment.xml @@ -32,8 +32,8 @@ android:layout_marginRight="10dp" android:layout_marginTop="3dp" android:layout_weight="0.5" - android:text="@string/careportal_temptarget" - android:textColor="@color/colorTempTargetButton" /> + android:text="@string/careportal_temporarytarget" + android:textColor="@color/colorWizardButton" />