receive BGs from xDrip and NSClient
This commit is contained in:
parent
04f1b37c51
commit
701e6a2055
27 changed files with 1572 additions and 384 deletions
|
@ -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$" />
|
||||||
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
@ -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"
|
||||||
|
@ -29,12 +32,11 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<!-- Receiver from NSClient -->
|
<!-- Receiver from NSClient -->
|
||||||
<receiver
|
<receiver
|
||||||
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>
|
13
app/src/main/java/info/nightscout/androidaps/Constants.java
Normal file
13
app/src/main/java/info/nightscout/androidaps/Constants.java
Normal 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;
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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";
|
||||||
|
}
|
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,85 +9,135 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
|
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
|
||||||
try {
|
try {
|
||||||
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);
|
||||||
// TODO: add bg support
|
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
|
||||||
} catch (SQLException e) {
|
// TODO: add bg support
|
||||||
log.error(DatabaseHelper.class.getName(), "Can't create database", e);
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
log.error(DatabaseHelper.class.getName(), "Can't create database", e);
|
||||||
}
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
|
||||||
try {
|
try {
|
||||||
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);
|
||||||
onCreate(database, connectionSource);
|
TableUtils.dropTable(connectionSource, BgReading.class, true);
|
||||||
} catch (SQLException e) {
|
onCreate(database, connectionSource);
|
||||||
log.error(DatabaseHelper.class.getName(), "Can't drop databases", e);
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
log.error(DatabaseHelper.class.getName(), "Can't drop databases", e);
|
||||||
}
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the database connections and clear any cached DAOs.
|
* Close the database connections and clear any cached DAOs.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
super.close();
|
super.close();
|
||||||
}
|
|
||||||
|
|
||||||
public void resetDatabases() {
|
|
||||||
try {
|
|
||||||
TableUtils.dropTable(connectionSource, TempBasal.class, true);
|
|
||||||
TableUtils.dropTable(connectionSource, Treatment.class, true);
|
|
||||||
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
|
|
||||||
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetTreatments() {
|
|
||||||
try {
|
|
||||||
|
|
||||||
TableUtils.dropTable(connectionSource, Treatment.class, true);
|
|
||||||
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dao<TempBasal, Long> getDaoTempBasals() throws SQLException {
|
|
||||||
return getDao(TempBasal.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dao<Treatment, Long> getDaoTreatments() throws SQLException {
|
public void resetDatabases() {
|
||||||
return getDao(Treatment.class);
|
try {
|
||||||
}
|
TableUtils.dropTable(connectionSource, TempBasal.class, true);
|
||||||
|
TableUtils.dropTable(connectionSource, Treatment.class, true);
|
||||||
|
TableUtils.dropTable(connectionSource, BgReading.class, true);
|
||||||
|
TableUtils.createTableIfNotExists(connectionSource, TempBasal.class);
|
||||||
|
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
|
||||||
|
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetTreatments() {
|
||||||
|
try {
|
||||||
|
|
||||||
|
TableUtils.dropTable(connectionSource, Treatment.class, true);
|
||||||
|
TableUtils.createTableIfNotExists(connectionSource, Treatment.class);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dao<TempBasal, Long> getDaoTempBasals() throws SQLException {
|
||||||
|
return getDao(TempBasal.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dao<Treatment, Long> getDaoTreatments() throws SQLException {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,8 +265,13 @@ public class TempBasalsFragment extends Fragment {
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onStatusEvent(final EventNewBG ev) {
|
public void onStatusEvent(final EventNewBG ev) {
|
||||||
updateTotalIOB();
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
recyclerView.getAdapter().notifyDataSetChanged();
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateTotalIOB();
|
||||||
|
recyclerView.getAdapter().notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -262,7 +279,7 @@ public class TempBasalsFragment extends Fragment {
|
||||||
super.setUserVisibleHint(isVisibleToUser);
|
super.setUserVisibleHint(isVisibleToUser);
|
||||||
|
|
||||||
if (isVisibleToUser)
|
if (isVisibleToUser)
|
||||||
updateTotalIOB();
|
updateTotalIOBIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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) {
|
||||||
initializeData();
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
initializeData();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onStatusEvent(final EventNewBG ev) {
|
public void onStatusEvent(final EventNewBG ev) {
|
||||||
updateTotalIOB();
|
getActivity().runOnUiThread(new Runnable() {
|
||||||
recyclerView.getAdapter().notifyDataSetChanged();
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateTotalIOB();
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
app/src/main/java/info/nightscout/utils/ToastUtils.java
Normal file
21
app/src/main/java/info/nightscout/utils/ToastUtils.java
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
70
app/src/main/res/layout/treatments_newtreatment_fragment.xml
Normal file
70
app/src/main/res/layout/treatments_newtreatment_fragment.xml
Normal 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>
|
332
app/src/main/res/layout/treatments_wizard_fragment.xml
Normal file
332
app/src/main/res/layout/treatments_wizard_fragment.xml
Normal 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>
|
|
@ -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" />
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue