receive BGs from xDrip and NSClient

This commit is contained in:
Milos Kozak 2016-06-07 21:48:17 +02:00
parent 04f1b37c51
commit 701e6a2055
27 changed files with 1572 additions and 384 deletions

View file

@ -3,8 +3,9 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="C:\Program Files\Android\Android Studio\gradle\gradle-2.10" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />

View file

@ -1,12 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AndroidLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintUselessParent" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintValidFragment" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
</inspection_tool>
</profile>
</component>

View file

@ -1,7 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Project Default" />
<option name="USE_PROJECT_PROFILE" value="true" />
<version value="1.0" />
</settings>
</component>

View file

@ -43,20 +43,4 @@
<component name="ProjectType"> <component name="ProjectType">
<option name="id" value="Android" /> <option name="id" value="Android" />
</component> </component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.8</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project> </project>

View file

@ -14,6 +14,9 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- To receive data from xdrip. -->
<uses-permission android:name="com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE" />
<application <application
android:name=".MainApp" android:name=".MainApp"
android:allowBackup="true" android:allowBackup="true"
@ -34,7 +37,6 @@
android:name="info.nightscout.client.receivers.NSClientDataReceiver" android:name="info.nightscout.client.receivers.NSClientDataReceiver"
android:enabled="true" android:enabled="true"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="info.nightscout.client.NEW_TREATMENT" /> <action android:name="info.nightscout.client.NEW_TREATMENT" />
<action android:name="info.nightscout.client.CHANGED_TREATMENT" /> <action android:name="info.nightscout.client.CHANGED_TREATMENT" />
@ -45,6 +47,21 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Receiver from xDrip -->
<receiver
android:name=".receivers.xDripReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.eveningoutpost.dexdrip.BgEstimate" />
</intent-filter>
</receiver>
<!-- Service processing incomming data -->
<service
android:name=".Services.DataService"
android:exported="false"></service>
</application> </application>
</manifest> </manifest>

View file

@ -0,0 +1,13 @@
package info.nightscout.androidaps;
/**
* Created by mike on 07.06.2016.
*/
public class Constants {
public static final String MGDL = "mg/dl"; // This is Nightscout representation
public static final String MMOL = "mmol";
public static final double MMOLL_TO_MGDL = 18.0182;
public static final double MGDL_TO_MMOLL = 1 / MMOLL_TO_MGDL;
}

View file

@ -1,7 +1,5 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
@ -12,15 +10,12 @@ import android.view.MenuItem;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.List;
import info.nightscout.androidaps.plugins.ProfileViewer.ProfileViewerFragment; import info.nightscout.androidaps.plugins.ProfileViewer.ProfileViewerFragment;
import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment; import info.nightscout.androidaps.plugins.TempBasals.TempBasalsFragment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment; import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.androidaps.tabs.*; import info.nightscout.androidaps.tabs.*;
import info.nightscout.androidaps.plugins.Objectives.ObjectivesFragment; import info.nightscout.androidaps.plugins.Objectives.ObjectivesFragment;
import info.nightscout.androidaps.plugins.Test.TestFragment; import info.nightscout.androidaps.plugins.Test.TestFragment;
import info.nightscout.client.broadcasts.Intents;
public class MainActivity extends AppCompatActivity public class MainActivity extends AppCompatActivity
implements ObjectivesFragment.OnFragmentInteractionListener, implements ObjectivesFragment.OnFragmentInteractionListener,
@ -33,6 +28,10 @@ public class MainActivity extends AppCompatActivity
private ViewPager mPager; private ViewPager mPager;
private TabPageAdapter mAdapter; private TabPageAdapter mAdapter;
public static TreatmentsFragment treatmentsFragment;
public static TempBasalsFragment tempBasalsFragment;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -41,8 +40,8 @@ public class MainActivity extends AppCompatActivity
// Register all tabs in app here // Register all tabs in app here
mAdapter = new TabPageAdapter(getSupportFragmentManager()); mAdapter = new TabPageAdapter(getSupportFragmentManager());
mAdapter.registerNewFragment("Test", TestFragment.newInstance()); mAdapter.registerNewFragment("Test", TestFragment.newInstance());
mAdapter.registerNewFragment("Treatments", TreatmentsFragment.newInstance()); mAdapter.registerNewFragment("Treatments", treatmentsFragment = TreatmentsFragment.newInstance());
mAdapter.registerNewFragment("TempBasals", TempBasalsFragment.newInstance()); mAdapter.registerNewFragment("TempBasals", tempBasalsFragment = TempBasalsFragment.newInstance());
mAdapter.registerNewFragment("Profile", ProfileViewerFragment.newInstance()); mAdapter.registerNewFragment("Profile", ProfileViewerFragment.newInstance());
mAdapter.registerNewFragment("Objectives", ObjectivesFragment.newInstance()); mAdapter.registerNewFragment("Objectives", ObjectivesFragment.newInstance());

View file

@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory;
import java.util.Date; import java.util.Date;
import info.nightscout.androidaps.data.Pump; import info.nightscout.androidaps.data.Pump;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.client.data.NSProfile; import info.nightscout.client.data.NSProfile;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;

View file

@ -0,0 +1,391 @@
package info.nightscout.androidaps.Services;
import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
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 org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.androidaps.tabs.Config;
import info.nightscout.client.data.NSProfile;
import info.nightscout.client.data.NSSgv;
public class DataService extends IntentService {
private static Logger log = LoggerFactory.getLogger(DataService.class);
Handler mHandler;
private HandlerThread mHandlerThread;
public DataService() {
super("DataService");
}
@Override
protected void onHandleIntent(Intent intent) {
if (Config.logFunctionCalls)
log.debug("onHandleIntent");
if (intent != null) {
final String action = intent.getAction();
if (Intents.ACTION_NEW_BG_ESTIMATE.equals(action)) {
handleNewDataFromXDrip(intent);
} else if (Intents.ACTION_NEW_PROFILE.equals(action) ||
Intents.ACTION_NEW_TREATMENT.equals(action) ||
Intents.ACTION_CHANGED_TREATMENT.equals(action) ||
Intents.ACTION_REMOVED_TREATMENT.equals(action) ||
Intents.ACTION_NEW_SGV.equals(action)
) {
handleNewDataFromNSClient(intent);
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (Config.logFunctionCalls)
log.debug("onStartCommand");
if (mHandlerThread == null) {
if (Config.detailedLog)
log.debug("Creating handler thread");
this.mHandlerThread = new HandlerThread(DataService.class.getSimpleName() + "Handler");
mHandlerThread.start();
this.mHandler = new Handler(mHandlerThread.getLooper());
registerBus();
}
return START_STICKY;
}
@Override
public void onDestroy() {
MainApp.bus().unregister(this);
}
private void registerBus() {
try {
MainApp.bus().unregister(this);
} catch (RuntimeException x) {
// Ignore
}
MainApp.bus().register(this);
}
private void handleNewDataFromXDrip(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
BgReading bgReading = new BgReading();
bgReading.value = bundle.getDouble(Intents.EXTRA_BG_ESTIMATE);
bgReading.slope = bundle.getDouble(Intents.EXTRA_BG_SLOPE);
bgReading.battery_level = bundle.getInt(Intents.EXTRA_SENSOR_BATTERY);
bgReading.timestamp = bundle.getLong(Intents.EXTRA_TIMESTAMP);
bgReading.raw = bundle.getDouble(Intents.EXTRA_RAW);
if (Config.logIncommingBG)
log.debug("XDRIPREC BG " + bgReading.toString());
try {
MainApp.instance().getDbHelper().getDaoBgReadings().update(bgReading);
} catch (SQLException e) {
e.printStackTrace();
}
MainApp.bus().post(new EventNewBG());
}
private void handleNewDataFromNSClient(Intent intent) {
Bundle bundles = intent.getExtras();
if (bundles == null) return;
// Handle profile
if (intent.getAction().equals(Intents.ACTION_NEW_PROFILE)) {
try {
String activeProfile = bundles.getString("activeprofile");
String profile = bundles.getString("profile");
NSProfile nsProfile = new NSProfile(new JSONObject(profile), activeProfile);
MainApp.instance().setNSProfile(nsProfile);
MainApp.instance().setActiveProfile(activeProfile);
storeNSProfile();
if (MainApp.getActivePump() != null) {
MainApp.getActivePump().setNewBasalProfile();
} else {
log.error("No active pump selected");
}
if (Config.logIncommingData)
log.debug("Received profile: " + activeProfile + " " + profile);
MainApp.bus().post(new EventNewBasalProfile());
} catch (JSONException e) {
e.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT)) {
try {
String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring);
if (!trJson.has("insulin") && !trJson.has("carbs")) {
if (Config.logIncommingData)
log.debug("ADD: Uninterested treatment: " + trstring);
return;
}
Treatment stored = null;
trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
if (trJson.has("timeIndex")) {
if (Config.logIncommingData)
log.debug("ADD: timeIndex found: " + trstring);
stored = findByTimeIndex(trJson.getLong("timeIndex"));
} else {
stored = findById(_id);
}
if (stored != null) {
if (Config.logIncommingData)
log.debug("ADD: Existing treatment: " + trstring);
if (trJson.has("timeIndex")) {
stored._id = _id;
MainApp.getDbHelper().getDaoTreatments().update(stored);
}
return;
} else {
if (Config.logIncommingData)
log.debug("ADD: New treatment: " + trstring);
Treatment treatment = new Treatment();
treatment._id = _id;
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
treatment.created_at = new Date(trJson.getLong("mills"));
treatment.setTimeIndex(treatment.getTimeIndex());
try {
MainApp.getDbHelper().getDaoTreatments().create(treatment);
if (Config.logIncommingData)
log.debug("ADD: Stored treatment: " + treatment.log());
MainApp.bus().post(new EventTreatmentChange());
} catch (SQLException e) {
e.printStackTrace();
}
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) {
try {
String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring);
if (!trJson.has("insulin") && !trJson.has("carbs")) {
if (Config.logIncommingData)
log.debug("CHANGE: Uninterested treatment: " + trstring);
return;
}
trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
Treatment stored;
if (trJson.has("timeIndex")) {
if (Config.logIncommingData)
log.debug("ADD: timeIndex found: " + trstring);
stored = findByTimeIndex(trJson.getLong("timeIndex"));
} else {
stored = findById(_id);
}
if (stored != null) {
if (Config.logIncommingData)
log.debug("CHANGE: Existing treatment: " + trstring);
stored._id = _id;
stored.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
stored.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
stored.created_at = new Date(trJson.getLong("mills"));
MainApp.getDbHelper().getDaoTreatments().update(stored);
MainApp.bus().post(new EventTreatmentChange());
} else {
if (Config.logIncommingData)
log.debug("CHANGE: New treatment: " + trstring);
Treatment treatment = new Treatment();
treatment._id = _id;
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
//treatment.created_at = DateUtil.fromISODateString(trJson.getString("created_at"));
treatment.created_at = new Date(trJson.getLong("mills"));
treatment.setTimeIndex(treatment.getTimeIndex());
try {
MainApp.getDbHelper().getDaoTreatments().create(treatment);
if (Config.logIncommingData)
log.debug("CHANGE: Stored treatment: " + treatment.log());
MainApp.bus().post(new EventTreatmentChange());
} catch (SQLException e) {
e.printStackTrace();
}
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_REMOVED_TREATMENT)) {
try {
if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
removeTreatmentFromDb(_id);
}
if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
String _id = trJson.getString("_id");
removeTreatmentFromDb(_id);
}
}
MainApp.bus().post(new EventTreatmentChange());
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_SGV)) {
try {
if (bundles.containsKey("sgv")) {
String sgvstring = bundles.getString("sgv");
JSONObject sgvJson = new JSONObject(sgvstring);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().getDaoBgReadings().update(bgReading);
if (Config.logIncommingData)
log.debug("ADD: Stored new BG: " + bgReading.toString());
}
if (bundles.containsKey("sgvs")) {
String sgvstring = bundles.getString("sgvs");
JSONArray jsonArray = new JSONArray(sgvstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject sgvJson = jsonArray.getJSONObject(i);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().getDaoBgReadings().update(bgReading);
if (Config.logIncommingData)
log.debug("ADD: Stored new BG: " + bgReading.toString());
}
}
MainApp.bus().post(new EventTreatmentChange());
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
MainApp.bus().post(new EventNewBG());
}
}
public void storeNSProfile() {
SharedPreferences settings = MainApp.instance().getApplicationContext().getSharedPreferences(MainApp.instance().PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("profile", MainApp.instance().getNSProfile().getData().toString());
editor.putString("activeProfile", MainApp.instance().getActiveProfile());
editor.commit();
}
public static Treatment findById(String _id) {
try {
QueryBuilder<Treatment, String> qb = null;
Dao<Treatment, Long> daoTreatments = MainApp.getDbHelper().getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
queryBuilder.limit(10);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
//log.debug("Treatment findById query size: " + trList.size());
return null;
} else {
//log.debug("Treatment findById found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static Treatment findByTimeIndex(Long timeIndex) {
try {
QueryBuilder<Treatment, String> qb = null;
Dao<Treatment, Long> daoTreatments = MainApp.getDbHelper().getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("timeIndex", timeIndex);
queryBuilder.limit(10);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
log.debug("Treatment findByTimeIndex query size: " + trList.size());
return null;
} else {
log.debug("Treatment findByTimeIndex found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private void removeTreatmentFromDb(String _id) throws SQLException {
Treatment stored = findById(_id);
if (stored != null) {
log.debug("REMOVE: Existing treatment (removing): " + _id);
MainApp.getDbHelper().getDaoTreatments().delete(stored);
MainApp.bus().post(new EventTreatmentChange());
} else {
log.debug("REMOVE: Not stored treatment (ignoring): " + _id);
}
}
}

View file

@ -0,0 +1,29 @@
package info.nightscout.androidaps.Services;
public interface Intents {
// NSClient -> App
String ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT";
String ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT";
String ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT";
String ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE";
String ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV";
String ACTION_NEW_STATUS = "info.nightscout.client.NEW_STATUS";
// App -> NSClient
String ACTION_DATABASE = "info.nightscout.client.DBACCESS";
String ACTION_RESTART = "info.nightscout.client.RESTART";
// xDrip -> App
String RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE";
String ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate";
String EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate";
String EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope";
String EXTRA_BG_SLOPE_NAME = "com.eveningoutpost.dexdrip.Extras.BgSlopeName";
String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw";
String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";
}

View file

@ -0,0 +1,87 @@
package info.nightscout.androidaps.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.Date;
import info.nightscout.androidaps.Constants;
import info.nightscout.client.data.NSCal;
import info.nightscout.client.data.NSSgv;
@DatabaseTable(tableName = "BgReadings")
public class BgReading {
private static Logger log = LoggerFactory.getLogger(BgReading.class);
public static final DecimalFormat mmolFormat = new DecimalFormat("0.0");
public static final DecimalFormat mgdlFormat = new DecimalFormat("0");
public long getTimeIndex() {
return (long) Math.ceil(timestamp / 60000d);
}
public void setTimeIndex(long timeIndex) {
this.timestamp = timeIndex;
}
@DatabaseField(id = true, useGetSet = true)
public long timeIndex;
@DatabaseField
public long timestamp;
@DatabaseField
public double value;
@DatabaseField
public double slope;
@DatabaseField
public double raw;
@DatabaseField
public int battery_level;
public BgReading() {}
public BgReading(NSSgv sgv) {
timestamp = sgv.getMills();
value = sgv.getMgdl();
raw = sgv.getFiltered();
}
public String valInUnit(String units) {
DecimalFormat formatMmol = new DecimalFormat("0.0");
DecimalFormat formatMgdl = new DecimalFormat("0");
if (units.equals(Constants.MGDL)) return formatMgdl.format(value);
else return formatMmol.format(value/18d);
}
public Double valueToUnits(String units) {
if (units.equals(Constants.MGDL))
return value;
else
return value * Constants.MGDL_TO_MMOLL;
}
public String valueToUnitsToString(String units) {
if (units.equals(Constants.MGDL)) return mgdlFormat.format(value);
else return mmolFormat.format(value * Constants.MGDL_TO_MMOLL);
}
@Override
public String toString() {
return "TempBasal{" +
"timeIndex=" + timeIndex +
", timestamp=" + timestamp +
", date=" + new Date(timestamp) +
", value=" + value +
", slope=" + slope +
", raw=" + raw +
", battery_level=" + battery_level +
'}';
}
}

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.db; package info.nightscout.androidaps.db;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Date;
import java.util.List; import java.util.List;
import android.content.Context; import android.content.Context;
@ -8,18 +9,22 @@ import android.database.sqlite.SQLiteDatabase;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils; import com.j256.ormlite.table.TableUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class); private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class);
public static final String DATABASE_NAME = "AndroidAPSDb"; public static final String DATABASE_NAME = "AndroidAPSDb";
private static final int DATABASE_VERSION = 2; private static final int DATABASE_VERSION = 1;
public DatabaseHelper(Context context) { public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);
@ -32,6 +37,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
log.info("onCreate"); log.info("onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class); TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class); TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
// TODO: add bg support // TODO: add bg support
} catch (SQLException e) { } catch (SQLException e) {
log.error(DatabaseHelper.class.getName(), "Can't create database", e); log.error(DatabaseHelper.class.getName(), "Can't create database", e);
@ -45,6 +51,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
log.info(DatabaseHelper.class.getName(), "onUpgrade"); log.info(DatabaseHelper.class.getName(), "onUpgrade");
TableUtils.dropTable(connectionSource, TempBasal.class, true); TableUtils.dropTable(connectionSource, TempBasal.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true); TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true);
onCreate(database, connectionSource); onCreate(database, connectionSource);
} catch (SQLException e) { } catch (SQLException e) {
log.error(DatabaseHelper.class.getName(), "Can't drop databases", e); log.error(DatabaseHelper.class.getName(), "Can't drop databases", e);
@ -64,8 +71,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try { try {
TableUtils.dropTable(connectionSource, TempBasal.class, true); TableUtils.dropTable(connectionSource, TempBasal.class, true);
TableUtils.dropTable(connectionSource, Treatment.class, true); TableUtils.dropTable(connectionSource, Treatment.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class); TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
TableUtils.createTableIfNotExists(connectionSource, Treatment.class); TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -89,4 +98,46 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(Treatment.class); return getDao(Treatment.class);
} }
public Dao<BgReading, Long> getDaoBgReadings() throws SQLException {
return getDao(BgReading.class);
}
/*
* Return last BgReading from database or null if db is empty
*/
public BgReading lastBg() {
List<BgReading> bgList = null;
try {
Dao<BgReading, Long> daoBgReadings = MainApp.getDbHelper().getDaoBgReadings();
QueryBuilder<BgReading, Long> queryBuilder = daoBgReadings.queryBuilder();
queryBuilder.orderBy("timeIndex", false);
queryBuilder.limit(1l);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgList = daoBgReadings.query(preparedQuery);
} catch (SQLException e) {
log.debug(e.getMessage(), e);
}
if (bgList.size() > 0)
return bgList.get(0);
else
return null;
}
/*
* Return bg reading if not old ( <9 min )
* or null if older
*/
public BgReading actualBg() {
BgReading lastBg = lastBg();
if (lastBg == null)
return null;
if (lastBg.timestamp > new Date().getTime() - 9 * 60 * 1000)
return lastBg;
return null;
}
} }

View file

@ -17,7 +17,7 @@ import java.util.Date;
import java.util.List; import java.util.List;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.client.broadcasts.Intents; import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.client.data.NSProfile; import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;

View file

@ -67,6 +67,7 @@ public class ProfileViewerFragment extends Fragment {
NSProfile profile = MainApp.getNSProfile(); NSProfile profile = MainApp.getNSProfile();
if (profile == null) { if (profile == null) {
noProfile.setVisibility(View.VISIBLE); noProfile.setVisibility(View.VISIBLE);
return;
} else { } else {
noProfile.setVisibility(View.GONE); noProfile.setVisibility(View.GONE);
} }

View file

@ -45,6 +45,9 @@ public class TempBasalsFragment extends Fragment {
TextView iobTotal; TextView iobTotal;
TextView activityTotal; TextView activityTotal;
public long lastCalculationTimestamp = 0;
public Iob lastCalculation;
private static DecimalFormat formatNumber0decimalplaces = new DecimalFormat("0"); private static DecimalFormat formatNumber0decimalplaces = new DecimalFormat("0");
private static DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00"); private static DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00");
private static DecimalFormat formatNumber3decimalplaces = new DecimalFormat("0.000"); private static DecimalFormat formatNumber3decimalplaces = new DecimalFormat("0.000");
@ -86,6 +89,15 @@ public class TempBasalsFragment extends Fragment {
updateTotalIOB(); updateTotalIOB();
} }
/*
* Recalculate IOB if value is older than 1 minute
*/
public void updateTotalIOBIfNeeded() {
if (lastCalculationTimestamp > new Date().getTime() - 60 * 1000)
return;
updateTotalIOB();
}
private void updateTotalIOB() { private void updateTotalIOB() {
Iob total = new Iob(); Iob total = new Iob();
for (Integer pos = 0; pos < tempBasals.size(); pos++) { for (Integer pos = 0; pos < tempBasals.size(); pos++) {
@ -253,16 +265,21 @@ public class TempBasalsFragment extends Fragment {
@Subscribe @Subscribe
public void onStatusEvent(final EventNewBG ev) { public void onStatusEvent(final EventNewBG ev) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
updateTotalIOB(); updateTotalIOB();
recyclerView.getAdapter().notifyDataSetChanged(); recyclerView.getAdapter().notifyDataSetChanged();
} }
});
}
@Override @Override
public void setUserVisibleHint(boolean isVisibleToUser) { public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser); super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) if (isVisibleToUser)
updateTotalIOB(); updateTotalIOBIfNeeded();
} }
/** /**

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.plugins.Treatments.Dialogs;
import android.app.Activity;
import android.app.DialogFragment;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.*;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
public class NewTreatmentDialogFragment extends DialogFragment implements OnClickListener {
Button deliverButton;
Communicator communicator;
TextView insulin;
TextView carbs;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof Communicator) {
communicator = (Communicator) getActivity();
} else {
throw new ClassCastException(activity.toString()
+ " must implemenet NewTreatmentDialogFragment.Communicator");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.treatments_newtreatment_fragment, null, false);
deliverButton = (Button) view.findViewById(R.id.treatments_newtreatment_deliverbutton);
deliverButton.setOnClickListener(this);
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
insulin = (TextView) view.findViewById(R.id.treatments_newtreatment_insulinamount);
carbs = (TextView) view.findViewById(R.id.treatments_newtreatment_carbsamount);
return view;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.treatments_newtreatment_deliverbutton:
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
Double maxbolus = Double.parseDouble(SP.getString("safety_maxbolus", "3"));
Double maxcarbs = Double.parseDouble(SP.getString("safety_maxcarbs", "48"));
String insulinText = this.insulin.getText().toString();
String carbsText = this.carbs.getText().toString();
Double insulin = Double.parseDouble(!insulinText.equals("") ? this.insulin.getText().toString() : "0");
Double carbs = Double.parseDouble(!carbsText.equals("") ? this.carbs.getText().toString() : "0");
if (insulin > maxbolus) {
this.insulin.setText("");
} else if (carbs > maxcarbs) {
this.carbs.setText("");
} else if (insulin > 0d || carbs > 0d) {
dismiss();
communicator.treatmentDeliverRequest(insulin, carbs);
}
break;
}
}
public interface Communicator {
void treatmentDeliverRequest(Double insulin, Double carbs);
}
}

View file

@ -0,0 +1,295 @@
package info.nightscout.androidaps.plugins.Treatments.Dialogs;
import android.app.Activity;
import android.app.DialogFragment;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.*;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import java.text.DecimalFormat;
import java.util.Date;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsFragment;
import info.nightscout.client.data.NSProfile;
import info.nightscout.utils.*;
public class WizardDialogFragment extends DialogFragment implements OnClickListener {
Button wizardDialogDeliverButton;
Communicator communicator;
TextView correctionInput;
TextView carbsInput;
TextView bgInput;
TextView bg, bgInsulin, bgUnits;
CheckBox bgCheckbox;
TextView carbs, carbsInsulin;
TextView iob, iobInsulin;
CheckBox iobCheckbox;
TextView correctionInsulin;
TextView total, totalInsulin;
public static final DecimalFormat numberFormat = new DecimalFormat("0.00");
public static final DecimalFormat intFormat = new DecimalFormat("0");
Double calculatedCarbs = 0d;
Double calculatedTotalInsulin = 0d;
final private TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start,int before, int count) {
calculateInsulin();
}
};
final CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
calculateInsulin();
}
};
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof Communicator) {
communicator = (Communicator) getActivity();
} else {
throw new ClassCastException(activity.toString()
+ " must implemenet WizardDialogFragment.Communicator");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.treatments_wizard_fragment, null, false);
wizardDialogDeliverButton = (Button) view.findViewById(R.id.treatments_wizard_deliverButton);
wizardDialogDeliverButton.setOnClickListener(this);
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
correctionInput = (TextView)view.findViewById(R.id.treatments_wizard_correctioninput);
carbsInput = (TextView)view.findViewById(R.id.treatments_wizard_carbsinput);
bgInput = (TextView)view.findViewById(R.id.treatments_wizard_bginput);
correctionInput.addTextChangedListener(textWatcher);
carbsInput.addTextChangedListener(textWatcher);
bgInput.addTextChangedListener(textWatcher);
bg = (TextView)view.findViewById(R.id.treatments_wizard_bg);
bgInsulin = (TextView)view.findViewById(R.id.treatments_wizard_bginsulin);
bgUnits = (TextView)view.findViewById(R.id.treatments_wizard_bgunits);
bgCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_bgcheckbox);
carbs = (TextView)view.findViewById(R.id.treatments_wizard_carbs);
carbsInsulin = (TextView)view.findViewById(R.id.treatments_wizard_carbsinsulin);
iob = (TextView)view.findViewById(R.id.treatments_wizard_iob);
iobInsulin = (TextView)view.findViewById(R.id.treatments_wizard_iobinsulin);
iobCheckbox = (CheckBox) view.findViewById(R.id.treatments_wizard_iobcheckbox);
correctionInsulin = (TextView)view.findViewById(R.id.treatments_wizard_correctioninsulin);
total = (TextView)view.findViewById(R.id.treatments_wizard_total);
totalInsulin = (TextView)view.findViewById(R.id.treatments_wizard_totalinsulin);
bgCheckbox.setOnCheckedChangeListener(onCheckedChangeListener);
iobCheckbox.setOnCheckedChangeListener(onCheckedChangeListener);
initDialog();
return view;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.treatments_wizard_deliverButton:
if (calculatedTotalInsulin > 0d || calculatedCarbs > 0d){
dismiss();
communicator.treatmentDialogDeliver(calculatedTotalInsulin, calculatedCarbs);
}
break;
}
}
private void initDialog() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
String units = SP.getString("ns_units", Constants.MGDL);
if (MainApp.getNSProfile() == null) {
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), "No profile loaded from NS yet");
dismiss();
return;
}
bgUnits.setText(units);
// Set BG if not old
BgReading lastBg = MainApp.getDbHelper().lastBg();
Double lastBgValue = lastBg.valueToUnits(units);
if (lastBg != null) {
Double sens = MainApp.getNSProfile().getIsf(MainApp.getNSProfile().secondsFromMidnight());
Double targetBGLow = MainApp.getNSProfile().getTargetLow(MainApp.getNSProfile().secondsFromMidnight());
Double targetBGHigh = MainApp.getNSProfile().getTargetHigh(MainApp.getNSProfile().secondsFromMidnight());
Double bgDiff;
if (lastBgValue <= targetBGLow) {
bgDiff = lastBgValue - targetBGLow;
} else {
bgDiff = lastBgValue - targetBGHigh;
}
bg.setText(lastBg.valueToUnitsToString(units) + " ISF: " + intFormat.format(sens));
bgInsulin.setText(numberFormat.format(bgDiff / sens) + "U");
bgInput.setText(lastBg.valueToUnitsToString(units));
} else {
bg.setText("");
bgInsulin.setText("");
bgInput.setText("");
}
// IOB calculation
MainActivity.treatmentsFragment.updateTotalIOBIfNeeded();
MainActivity.tempBasalsFragment.updateTotalIOBIfNeeded();
Iob bolusIob = MainActivity.treatmentsFragment.lastCalculation;
Iob basalIob = MainActivity.tempBasalsFragment.lastCalculation;
bolusIob.plus(basalIob);
iobInsulin.setText("-" + numberFormat.format(bolusIob.iobContrib) + "U");
totalInsulin.setText("");
wizardDialogDeliverButton.setVisibility(Button.GONE);
}
private void calculateInsulin() {
SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext());
Double maxbolus = Double.parseDouble(SP.getString("safety_maxbolus", "3"));
Double maxcarbs = Double.parseDouble(SP.getString("safety_maxcarbs", "48"));
String units = SP.getString("ns_units", Constants.MGDL);
NSProfile profile = MainApp.instance().getNSProfile();
// Entered values
String i_bg = this.bgInput.getText().toString();
String i_carbs = this.carbsInput.getText().toString();
String i_correction = this.correctionInput.getText().toString();
Double c_bg = 0d;
try { c_bg = Double.parseDouble(i_bg.equals("") ? "0" : i_bg); } catch (Exception e) {}
Double c_carbs = 0d;
try { c_carbs = Double.parseDouble(i_carbs.equals("") ? "0" : i_carbs); } catch (Exception e) {}
c_carbs = ((Long)Math.round(c_carbs)).doubleValue();
Double c_correction = 0d;
try { c_correction = Double.parseDouble(i_correction.equals("") ? "0" : i_correction); } catch (Exception e) {}
if(c_correction > maxbolus) {
this.correctionInput.setText("");
wizardDialogDeliverButton.setVisibility(Button.GONE);
return;
}
if(c_carbs > maxcarbs) {
this.carbsInput.setText("");
wizardDialogDeliverButton.setVisibility(Button.GONE);
return;
}
// Insulin from BG
Double sens = profile.getIsf(MainApp.getNSProfile().secondsFromMidnight());
Double targetBGLow = profile.getTargetLow(MainApp.getNSProfile().secondsFromMidnight());
Double targetBGHigh = profile.getTargetHigh(MainApp.getNSProfile().secondsFromMidnight());
Double bgDiff;
if (c_bg <= targetBGLow) {
bgDiff = c_bg - targetBGLow;
} else {
bgDiff = c_bg - targetBGHigh;
}
Double insulinFromBG = (bgCheckbox.isChecked() && c_bg != 0d) ? bgDiff /sens : 0d;
bg.setText(c_bg + " ISF: " + intFormat.format(sens));
bgInsulin.setText(numberFormat.format(insulinFromBG) + "U");
// Insuling from carbs
Double ic = profile.getIc(MainApp.getNSProfile().secondsFromMidnight());
Double insulinFromCarbs = c_carbs / ic;
carbs.setText(intFormat.format(c_carbs) + "g IC: " + intFormat.format(ic));
carbsInsulin.setText(numberFormat.format(insulinFromCarbs) + "U");
// Insulin from IOB
MainActivity.treatmentsFragment.updateTotalIOBIfNeeded();
MainActivity.tempBasalsFragment.updateTotalIOBIfNeeded();
Iob bolusIob = MainActivity.treatmentsFragment.lastCalculation;
Iob basalIob = MainActivity.tempBasalsFragment.lastCalculation;
bolusIob.plus(basalIob);
Double insulingFromIOB = iobCheckbox.isChecked() ? bolusIob.iobContrib : 0d;
iobInsulin.setText("-" + numberFormat.format(insulingFromIOB) + "U");
// Insulin from correction
Double insulinFromCorrection = c_correction;
correctionInsulin.setText(numberFormat.format(insulinFromCorrection) + "U");
// Total
calculatedTotalInsulin = insulinFromBG + insulinFromCarbs - insulingFromIOB + insulinFromCorrection;
if (calculatedTotalInsulin < 0) {
Double carbsEquivalent = -calculatedTotalInsulin * ic;
total.setText("Missing " + intFormat.format(carbsEquivalent) + "g");
calculatedTotalInsulin = 0d;
totalInsulin.setText("");
} else {
calculatedTotalInsulin = roundTo(calculatedTotalInsulin, 0.05d);
total.setText("");
totalInsulin.setText(numberFormat.format(calculatedTotalInsulin) + "U");
}
calculatedCarbs = c_carbs;
if (calculatedTotalInsulin > 0d || calculatedCarbs > 0d) {
String insulinText = calculatedTotalInsulin > 0d ? (numberFormat.format(calculatedTotalInsulin) + "U") : "";
String carbsText = calculatedCarbs > 0d ? (intFormat.format(calculatedCarbs) + "g") : "";
wizardDialogDeliverButton.setText("SEND " + insulinText + " " + carbsText);
wizardDialogDeliverButton.setVisibility(Button.VISIBLE);
} else {
wizardDialogDeliverButton.setVisibility(Button.GONE);
}
}
private double fromMgdl(Double value, String units) {
if (units.equals(Constants.MGDL)) return value;
else return value / 18;
}
private Double roundTo(Double x, Double step) {
if (x != 0d) {
return Math.round(x / step) * step;
}
return 0d;
}
public interface Communicator {
void treatmentDialogDeliver(Double insulin, Double carbs);
}
}

View file

@ -31,16 +31,17 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import info.nightscout.androidaps.MainActivity;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Iob; import info.nightscout.androidaps.data.Iob;
import info.nightscout.androidaps.db.Treatment; import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.EventNewBG; import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventTreatmentChange; import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.client.broadcasts.Intents; import info.nightscout.androidaps.plugins.Treatments.Dialogs.NewTreatmentDialogFragment;
import info.nightscout.androidaps.Services.Intents;
public class TreatmentsFragment extends Fragment implements View.OnClickListener { public class TreatmentsFragment extends Fragment implements View.OnClickListener, NewTreatmentDialogFragment.Communicator {
private static Logger log = LoggerFactory.getLogger(TreatmentsFragment.class); private static Logger log = LoggerFactory.getLogger(TreatmentsFragment.class);
RecyclerView recyclerView; RecyclerView recyclerView;
@ -50,6 +51,9 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
TextView activityTotal; TextView activityTotal;
Button refreshFromNS; Button refreshFromNS;
public long lastCalculationTimestamp = 0;
public Iob lastCalculation;
private static DecimalFormat formatNumber0decimalplaces = new DecimalFormat("0"); private static DecimalFormat formatNumber0decimalplaces = new DecimalFormat("0");
private static DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00"); private static DecimalFormat formatNumber2decimalplaces = new DecimalFormat("0.00");
private static DecimalFormat formatNumber3decimalplaces = new DecimalFormat("0.000"); private static DecimalFormat formatNumber3decimalplaces = new DecimalFormat("0.000");
@ -76,6 +80,15 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
updateTotalIOB(); updateTotalIOB();
} }
/*
* Recalculate IOB if value is older than 1 minute
*/
public void updateTotalIOBIfNeeded() {
if (lastCalculationTimestamp > new Date().getTime() - 60 * 1000)
return;
updateTotalIOB();
}
private void updateTotalIOB() { private void updateTotalIOB() {
Iob total = new Iob(); Iob total = new Iob();
for (Integer pos = 0; pos < treatments.size(); pos++) { for (Integer pos = 0; pos < treatments.size(); pos++) {
@ -86,6 +99,9 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
iobTotal.setText(formatNumber2decimalplaces.format(total.iobContrib)); iobTotal.setText(formatNumber2decimalplaces.format(total.iobContrib));
if (activityTotal != null) if (activityTotal != null)
activityTotal.setText(formatNumber3decimalplaces.format(total.activityContrib)); activityTotal.setText(formatNumber3decimalplaces.format(total.activityContrib));
lastCalculationTimestamp = new Date().getTime();
lastCalculation = total;
} }
public static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TreatmentsViewHolder> { public static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TreatmentsViewHolder> {
@ -233,13 +249,23 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
@Subscribe @Subscribe
public void onStatusEvent(final EventTreatmentChange ev) { public void onStatusEvent(final EventTreatmentChange ev) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
initializeData(); initializeData();
} }
});
}
@Subscribe @Subscribe
public void onStatusEvent(final EventNewBG ev) { public void onStatusEvent(final EventNewBG ev) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
updateTotalIOB(); updateTotalIOB();
recyclerView.getAdapter().notifyDataSetChanged(); recyclerView.getAdapter().notifyDataSetChanged(); }
});
} }
@Override @Override
@ -247,7 +273,7 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
super.setUserVisibleHint(isVisibleToUser); super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) if (isVisibleToUser)
updateTotalIOB(); updateTotalIOBIfNeeded();
} }
/** /**
@ -264,4 +290,10 @@ public class TreatmentsFragment extends Fragment implements View.OnClickListener
// TODO: Update argument type and name // TODO: Update argument type and name
void onFragmentInteraction(String param); void onFragmentInteraction(String param);
} }
@Override
public void treatmentDeliverRequest(Double insulin, Double carbs) {
// TODO: implement treatment delivery
}
} }

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.receivers;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Services.DataService;
import info.nightscout.androidaps.tabs.Config;
public class xDripReceiver extends WakefulBroadcastReceiver {
private static Logger log = LoggerFactory.getLogger(xDripReceiver.class);
@Override
public void onReceive(Context context, Intent intent) {
if (Config.logFunctionCalls)
log.debug("onReceive " + intent);
startWakefulService(context, new Intent(context, DataService.class)
.setAction(intent.getAction())
.putExtras(intent));
}
}

View file

@ -0,0 +1,11 @@
package info.nightscout.androidaps.tabs;
/**
* Created by mike on 07.06.2016.
*/
public class Config {
public static final boolean detailedLog = true;
public static final boolean logFunctionCalls = true;
public static final boolean logIncommingBG = true;
public static final boolean logIncommingData = true;
}

View file

@ -1,16 +0,0 @@
package info.nightscout.client.broadcasts;
public interface Intents {
// NSClient -> App
String ACTION_NEW_TREATMENT = "info.nightscout.client.NEW_TREATMENT";
String ACTION_CHANGED_TREATMENT = "info.nightscout.client.CHANGED_TREATMENT";
String ACTION_REMOVED_TREATMENT = "info.nightscout.client.REMOVED_TREATMENT";
String ACTION_NEW_PROFILE = "info.nightscout.client.NEW_PROFILE";
String ACTION_NEW_SGV = "info.nightscout.client.NEW_SGV";
String ACTION_NEW_STATUS = "info.nightscout.client.NEW_STATUS";
// App -> NSClient
String ACTION_DATABASE = "info.nightscout.client.DBACCESS";
String ACTION_RESTART = "info.nightscout.client.RESTART";
}

View file

@ -1,264 +1,24 @@
package info.nightscout.client.receivers; package info.nightscout.client.receivers;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.support.v4.content.WakefulBroadcastReceiver;
import android.os.Bundle;
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 org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.sql.SQLException; import info.nightscout.androidaps.Services.DataService;
import java.util.Date; import info.nightscout.androidaps.tabs.Config;
import java.util.List;
import info.nightscout.androidaps.events.EventNewBG; public class NSClientDataReceiver extends WakefulBroadcastReceiver {
import info.nightscout.androidaps.events.EventNewBasalProfile;
import info.nightscout.androidaps.events.EventTreatmentChange;
import info.nightscout.client.broadcasts.Intents;
import info.nightscout.client.data.NSProfile;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.db.Treatment;
public class NSClientDataReceiver extends BroadcastReceiver {
private static Logger log = LoggerFactory.getLogger(NSClientDataReceiver.class); private static Logger log = LoggerFactory.getLogger(NSClientDataReceiver.class);
public NSClientDataReceiver() {
}
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Bundle bundles = intent.getExtras(); if (Config.logFunctionCalls)
if (bundles == null) return; log.debug("onReceive " + intent);
startWakefulService(context, new Intent(context, DataService.class)
.setAction(intent.getAction())
// Handle profile .putExtras(intent));
if (intent.getAction().equals(Intents.ACTION_NEW_PROFILE)){
try {
String activeProfile = bundles.getString("activeprofile");
String profile = bundles.getString("profile");
NSProfile nsProfile = new NSProfile(new JSONObject(profile), activeProfile);
MainApp.instance().setNSProfile(nsProfile);
MainApp.instance().setActiveProfile(activeProfile);
storeNSProfile();
if (MainApp.getActivePump() != null) {
MainApp.getActivePump().setNewBasalProfile();
} else {
log.error("No active pump selected");
}
log.debug("Received profile: " + activeProfile + " " + profile);
MainApp.bus().post(new EventNewBasalProfile());
} catch (JSONException e) {
e.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_TREATMENT)) {
try {
String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring);
if (!trJson.has("insulin") && !trJson.has("carbs")) {
log.debug("ADD: Uninterested treatment: " + trstring);
return;
}
Treatment stored = null;
trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
if (trJson.has("timeIndex")) {
log.debug("ADD: timeIndex found: " + trstring);
stored = findByTimeIndex(trJson.getLong("timeIndex"));
} else {
stored = findById(_id);
}
if (stored != null) {
log.debug("ADD: Existing treatment: " + trstring);
if (trJson.has("timeIndex")) {
stored._id = _id;
MainApp.getDbHelper().getDaoTreatments().update(stored);
}
return;
} else {
log.debug("ADD: New treatment: " + trstring);
Treatment treatment = new Treatment();
treatment._id = _id;
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
treatment.created_at = new Date(trJson.getLong("mills"));
treatment.setTimeIndex(treatment.getTimeIndex());
try {
MainApp.getDbHelper().getDaoTreatments().create(treatment);
log.debug("ADD: Stored treatment: " + treatment.log());
MainApp.bus().post(new EventTreatmentChange());
} catch (SQLException e) {
e.printStackTrace();
}
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_CHANGED_TREATMENT)) {
try {
String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring);
if (!trJson.has("insulin") && !trJson.has("carbs")) {
log.debug("CHANGE: Uninterested treatment: " + trstring);
return;
}
trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
Treatment stored;
if (trJson.has("timeIndex")) {
log.debug("ADD: timeIndex found: " + trstring);
stored = findByTimeIndex(trJson.getLong("timeIndex"));
} else {
stored = findById(_id);
}
if (stored != null) {
log.debug("CHANGE: Existing treatment: " + trstring);
stored._id = _id;
stored.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
stored.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
stored.created_at = new Date(trJson.getLong("mills"));
MainApp.getDbHelper().getDaoTreatments().update(stored);
MainApp.bus().post(new EventTreatmentChange());
} else {
log.debug("CHANGE: New treatment: " + trstring);
Treatment treatment = new Treatment();
treatment._id = _id;
treatment.carbs = trJson.has("carbs") ? trJson.getDouble("carbs") : 0;
treatment.insulin = trJson.has("insulin") ? trJson.getDouble("insulin") : 0d;
//treatment.created_at = DateUtil.fromISODateString(trJson.getString("created_at"));
treatment.created_at = new Date(trJson.getLong("mills"));
treatment.setTimeIndex(treatment.getTimeIndex());
try {
MainApp.getDbHelper().getDaoTreatments().create(treatment);
log.debug("CHANGE: Stored treatment: " + treatment.log());
MainApp.bus().post(new EventTreatmentChange());
} catch (SQLException e) {
e.printStackTrace();
}
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_REMOVED_TREATMENT)) {
try {
if (bundles.containsKey("treatment")) {
String trstring = bundles.getString("treatment");
JSONObject trJson = new JSONObject(trstring);
String _id = trJson.getString("_id");
removeTreatmentFromDb(_id);
}
if (bundles.containsKey("treatments")) {
String trstring = bundles.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject trJson = jsonArray.getJSONObject(i);
String _id = trJson.getString("_id");
removeTreatmentFromDb(_id);
}
}
MainApp.bus().post(new EventTreatmentChange());
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
if (intent.getAction().equals(Intents.ACTION_NEW_SGV)) {
MainApp.bus().post(new EventNewBG());
}
}
public void storeNSProfile() {
SharedPreferences settings = MainApp.instance().getApplicationContext().getSharedPreferences(MainApp.instance().PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("profile", MainApp.instance().getNSProfile().getData().toString());
editor.putString("activeProfile", MainApp.instance().getActiveProfile());
editor.commit();
}
public static Treatment findById(String _id) {
try {
QueryBuilder<Treatment, String> qb = null;
Dao<Treatment, Long> daoTreatments = MainApp.getDbHelper().getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("_id", _id);
queryBuilder.limit(10);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
//log.debug("Treatment findById query size: " + trList.size());
return null;
} else {
//log.debug("Treatment findById found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static Treatment findByTimeIndex(Long timeIndex) {
try {
QueryBuilder<Treatment, String> qb = null;
Dao<Treatment, Long> daoTreatments = MainApp.getDbHelper().getDaoTreatments();
QueryBuilder<Treatment, Long> queryBuilder = daoTreatments.queryBuilder();
Where where = queryBuilder.where();
where.eq("timeIndex", timeIndex);
queryBuilder.limit(10);
PreparedQuery<Treatment> preparedQuery = queryBuilder.prepare();
List<Treatment> trList = daoTreatments.query(preparedQuery);
if (trList.size() != 1) {
log.debug("Treatment findByTimeIndex query size: " + trList.size());
return null;
} else {
log.debug("Treatment findByTimeIndex found: " + trList.get(0).log());
return trList.get(0);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private void removeTreatmentFromDb(String _id) throws SQLException {
Treatment stored = findById(_id);
if (stored != null) {
log.debug("REMOVE: Existing treatment (removing): " + _id);
MainApp.getDbHelper().getDaoTreatments().delete(stored);
MainApp.bus().post(new EventTreatmentChange());
} else {
log.debug("REMOVE: Not stored treatment (ignoring): " + _id);
}
} }
} }

View file

@ -0,0 +1,21 @@
package info.nightscout.utils;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
public class ToastUtils {
public static void showToastInUiThread(final Context ctx,
final String string) {
Handler mainThread = new Handler(Looper.getMainLooper());
mainThread.post(new Runnable() {
@Override
public void run() {
Toast.makeText(ctx, string, Toast.LENGTH_SHORT).show();
}
});
}
}

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/treatments_newtreatment_insulinamount_label"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_gravity="center_horizontal"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:id="@+id/treatments_newtreatment_insulinamount"
android:padding="10dp"
android:minWidth="200dp"
android:layout_gravity="center_horizontal"
android:inputType="numberDecimal"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/treatments_newtreatment_carbsamount_label"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_gravity="center_horizontal"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:id="@+id/treatments_newtreatment_carbsamount"
android:padding="10dp"
android:minWidth="200dp"
android:layout_gravity="center_horizontal"
android:inputType="numberDecimal"/>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp">
<Button
android:id="@+id/treatments_newtreatment_deliverbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OK"
android:textSize="20sp"
android:padding="10dp"
android:layout_weight="1"
/>
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,332 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/treatments_wizard_bg_label"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_gravity="center_horizontal"
android:width="80dp" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/treatments_wizard_bginput"
android:padding="10dp"
android:layout_gravity="center_horizontal"
android:inputType="numberDecimal"
android:gravity="center_horizontal"
android:layout_weight="0.5" />
<TextView
android:id="@+id/treatments_wizard_bgunits"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="mg/dl"
android:layout_gravity="center_vertical"
android:gravity="left"
android:paddingLeft="5dp"
android:minWidth="40dp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/treatments_wizard_carbs_label"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_gravity="center_horizontal"
android:width="80dp" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:id="@+id/treatments_wizard_carbsinput"
android:padding="10dp"
android:minWidth="200dp"
android:layout_gravity="center_horizontal"
android:inputType="numberDecimal"
android:gravity="center_horizontal"
android:layout_weight="0.5" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="g"
android:layout_gravity="center_vertical"
android:gravity="left"
android:paddingLeft="5dp"
android:minWidth="40dp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@string/treatments_wizard_correction_label"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_gravity="center_horizontal"
android:width="80dp" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:id="@+id/treatments_wizard_correctioninput"
android:padding="10dp"
android:minWidth="200dp"
android:layout_gravity="center_horizontal"
android:inputType="numberSigned|numberDecimal"
android:gravity="center_horizontal"
android:layout_weight="0.5" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/treatments_wizard_unit_label"
android:layout_gravity="center_vertical"
android:gravity="left"
android:paddingLeft="5dp"
android:minWidth="40dp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="32dp"
android:id="@+id/treatments_wizard_bgcheckbox"
android:checked="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/treatments_wizard_bg_label"
android:width="50dp"
android:id="@+id/textView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:width="100dp"
android:id="@+id/treatments_wizard_bg" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/treatments_wizard_bginsulin"
android:width="50dp"
android:gravity="end" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="32dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/treatments_wizard_carbs_label"
android:width="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:width="100dp"
android:id="@+id/treatments_wizard_carbs" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/treatments_wizard_carbsinsulin"
android:width="50dp"
android:gravity="end" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="32dp"
android:id="@+id/treatments_wizard_iobcheckbox"
android:checked="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/treatments_wizard_iob_label"
android:width="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:width="100dp"
android:id="@+id/treatments_wizard_iob" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/treatments_wizard_iobinsulin"
android:width="50dp"
android:gravity="end" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="32dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/treatments_wizard_correction_label"
android:width="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:width="100dp"
android:id="@+id/treatments_wizard_correction" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/treatments_wizard_correctioninsulin"
android:width="50dp"
android:gravity="end" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:width="32dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="bold"
android:text="@string/treatments_wizard_total_label"
android:width="50dp"
android:height="30dp"
android:gravity="center_vertical"
android:textColor="@color/accent_material_light" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:width="100dp"
android:id="@+id/treatments_wizard_total" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textStyle="bold"
android:id="@+id/treatments_wizard_totalinsulin"
android:width="50dp"
android:gravity="center_vertical|end"
android:textColor="@color/accent_material_light" />
</LinearLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_gravity="right">
<Button
android:id="@+id/treatments_wizard_deliverButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SEND TO PUMP"
android:textSize="20sp"
android:padding="10dp"
android:layout_weight="1"
android:textAllCaps="false"
/>
</LinearLayout>
</LinearLayout>

View file

@ -1,15 +1,9 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity"> tools:context=".MainActivity">
<item
android:id="@+id/nav_home"
android:title="@string/nav_home" />
<item <item
android:id="@+id/nav_preferences" android:id="@+id/nav_preferences"
android:title="@string/nav_preferences" /> android:title="@string/nav_preferences" />
<item
android:id="@+id/nav_refreshtreatments"
android:title="@string/nav_refreshtreatments" />
<item <item
android:id="@+id/nav_resetdb" android:id="@+id/nav_resetdb"
android:title="@string/nav_resetdb" /> android:title="@string/nav_resetdb" />

View file

@ -47,5 +47,13 @@
<string name="tempbasals_activity_string">Activity:</string> <string name="tempbasals_activity_string">Activity:</string>
<string name="tempbasals_iobtotal_label_string">Total IOB:</string> <string name="tempbasals_iobtotal_label_string">Total IOB:</string>
<string name="tempbasals_iobactivitytotal_label_string">Total IOB activity:</string> <string name="tempbasals_iobactivitytotal_label_string">Total IOB activity:</string>
<string name="treatments_newtreatment_insulinamount_label">Insulin amount</string>
<string name="treatments_newtreatment_carbsamount_label">Carbs amount</string>
<string name="treatments_wizard_bg_label">BG</string>
<string name="treatments_wizard_carbs_label">Carbs</string>
<string name="treatments_wizard_correction_label">Corr</string>
<string name="treatments_wizard_unit_label">U</string>
<string name="treatments_wizard_iob_label">IOB</string>
<string name="treatments_wizard_total_label">TOTAL</string>
</resources> </resources>