Merge pull request #6 from nightscout/dev

Dev
This commit is contained in:
Andreas 2021-02-11 15:31:17 +01:00 committed by GitHub
commit fdb585eaca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
738 changed files with 16909 additions and 8855 deletions

8
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: gradle
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
target-branch: dev

View file

@ -1,6 +1,5 @@
buildscript {
repositories {
jcenter()
maven { url "https://plugins.gradle.org/m2/" } // jacoco 0.2
}
@ -11,7 +10,6 @@ buildscript {
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.gms.google-services'
//apply plugin: 'jacoco-android'
@ -23,7 +21,6 @@ jacoco {
}
repositories {
jcenter { url "https://jcenter.bintray.com/" }
mavenCentral()
google()
}
@ -157,8 +154,8 @@ android {
ext.enableCrashlytics = false
}
}
flavorDimensions "standard"
productFlavors {
flavorDimensions "standard"
full {
applicationId "info.nightscout.androidaps"
dimension "standard"
@ -236,24 +233,29 @@ dependencies {
wearApp project(':wear')
implementation project(':core')
implementation project(':database')
implementation project(':dana')
implementation project(':danars')
implementation project(':danar')
implementation project(':rileylink')
implementation project(':medtronic')
implementation project(':omnipod')
implementation project(':omnipod-eros')
implementation project(':omnipod-dash')
implementation fileTree(include: ['*.jar'], dir: 'libs')
// https://github.com/DavidProdinger/Weekdays-Selector (used outdated 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1')
implementation(name: 'weekdaysselector-1.1.1', ext: 'aar')
testImplementation "junit:junit:$junit_version"
testImplementation 'org.json:json:20200518'
testImplementation 'org.json:json:20201115'
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
testImplementation "org.powermock:powermock-api-mockito2:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule-agent:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
testImplementation 'joda-time:joda-time:2.10.6'
testImplementation('com.google.truth:truth:1.0.1') {
testImplementation "joda-time:joda-time:$jodatime_version"
testImplementation('com.google.truth:truth:1.1.2') {
exclude group: "com.google.guava", module: "guava"
exclude group: "com.google.code.findbugs", module: "jsr305"
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -3,7 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="info.nightscout.androidaps">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
@ -136,10 +135,6 @@
android:resource="@xml/filepaths" />
</provider>
<!-- Service processing incomming data -->
<service
android:name=".services.DataService"
android:exported="false" />
<service
android:name=".services.LocationService"
android:exported="false" />

View file

@ -4,4 +4,7 @@
55:5D:70:C9:BE:10:41:7E:4B:01:A9:C4:C6:44:4A:F8:69:71:35:25:ED:95:23:16:C7:15:E8:EB:C6:08:FC:B1
# àqΣnΖ`ZϼγwÛ/τàΒϳ9Φ'$ΑϵžλUΛ`ÆÌΣЃA
E0:71:A3:6E:96:60:5A:FC:B3:77:DB:2F:C4:E0:92:F3:39:A6:27:24:91:F5:7E:BB:55:9B:60:C6:CC:A3:03:41
# 2ΙšÄΠΒϨÒÇeЄtЄЗž-*Ж*ZcHijЊÄœ<|x"Ε
32:99:61:C4:A0:92:E8:D2:C7:65:04:74:04:17:7E:2D:2A:16:2A:5A:63:48:69:6A:0A:C4:53:3C:7C:78:22:95
# mςRr¡ЇζΛLφK&ĐΨ5CnЎϴPDñЍŒkϼ{ΨδwВb
6D:C2:52:72:A1:07:B6:9B:4C:C6:4B:26:10:A8:35:43:6E:0E:F4:50:44:F1:0D:52:6B:FC:7B:A8:B4:77:12:62

View file

@ -57,10 +57,10 @@ import info.nightscout.androidaps.utils.extensions.isRunningRealPumpTest
import info.nightscout.androidaps.utils.locale.LocaleHelper
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.IconsProvider
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.tabs.TabPageAdapter
import info.nightscout.androidaps.utils.ui.UIRunnable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import java.util.*
import javax.inject.Inject
@ -71,6 +71,7 @@ class MainActivity : NoSplashAppCompatActivity() {
private val disposable = CompositeDisposable()
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var androidPermission: AndroidPermission
@Inject lateinit var sp: SP
@ -125,7 +126,7 @@ class MainActivity : NoSplashAppCompatActivity() {
setupViews()
disposable.add(rxBus
.toObservable(EventRebuildTabs::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
if (it.recreate) recreate()
else setupViews()
@ -134,7 +135,7 @@ class MainActivity : NoSplashAppCompatActivity() {
)
disposable.add(rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({ processPreferenceChange(it) }, fabricPrivacy::logException)
)
if (!sp.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) {

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
@ -19,6 +18,9 @@ import javax.inject.Inject;
import dagger.android.AndroidInjector;
import dagger.android.DaggerApplication;
import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.transactions.VersionChangeTransaction;
import info.nightscout.androidaps.db.CompatDBHelper;
import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.db.StaticInjector;
import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent;
@ -39,14 +41,14 @@ import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.utils.ActivityMonitor;
import info.nightscout.androidaps.utils.locale.LocaleHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
public class MainApp extends DaggerApplication {
static MainApp sInstance;
private static Resources sResources;
static DatabaseHelper sDatabaseHelper = null;
private final CompositeDisposable disposable = new CompositeDisposable();
@Inject PluginStore pluginStore;
@Inject AAPSLogger aapsLogger;
@Inject ActivityMonitor activityMonitor;
@ -58,6 +60,8 @@ public class MainApp extends DaggerApplication {
@Inject ConfigBuilderPlugin configBuilderPlugin;
@Inject KeepAliveReceiver.KeepAliveManager keepAliveManager;
@Inject List<PluginBase> plugins;
@Inject CompatDBHelper compatDBHelper;
@Inject AppRepository repository;
@Inject StaticInjector staticInjector; // TODO avoid , here fake only to initialize
@ -66,10 +70,8 @@ public class MainApp extends DaggerApplication {
super.onCreate();
aapsLogger.debug("onCreate");
sInstance = this;
sResources = getResources();
LocaleHelper.INSTANCE.update(this);
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
sDatabaseHelper = OpenHelperManager.getHelper(this, DatabaseHelper.class);
/*
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
if (ex instanceof InternalError) {
@ -79,6 +81,15 @@ public class MainApp extends DaggerApplication {
aapsLogger.error("Uncaught exception crashing app", ex);
});
*/
String gitRemote = BuildConfig.REMOTE;
String commitHash = BuildConfig.HEAD;
if (gitRemote.contains("NoGitSystemAvailable")) {
gitRemote = null;
commitHash = null;
}
disposable.add(repository.runTransaction(new VersionChangeTransaction(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, gitRemote, commitHash)).subscribe());
disposable.add(compatDBHelper.dbChangeDisposable());
registerActivityLifecycleCallbacks(activityMonitor);
JodaTimeAndroid.init(this);
@ -121,7 +132,6 @@ public class MainApp extends DaggerApplication {
.build();
}
@SuppressWarnings("deprecation")
private void registerLocalBroadcastReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intents.ACTION_NEW_TREATMENT);

View file

@ -0,0 +1,43 @@
package info.nightscout.androidaps.db
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.interfaces.TraceableDBEntry
import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.events.EventTempTargetChange
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData
import io.reactivex.disposables.Disposable
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompatDBHelper @Inject constructor(
val aapsLogger: AAPSLogger,
val repository: AppRepository,
val rxBus: RxBusWrapper
) {
fun dbChangeDisposable(): Disposable = repository
.changeObservable()
.doOnSubscribe {
rxBus.send(EventNewBG(null))
}
.subscribe {
it.filterIsInstance<GlucoseValue>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewHistoryData")
rxBus.send(EventNewHistoryData(it.timestamp))
}
it.filterIsInstance<GlucoseValue>().lastOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg")
rxBus.send(EventNewBG(it))
}
it.filterIsInstance<TemporaryTarget>().firstOrNull()?.let {
aapsLogger.debug(LTag.DATABASE, "Firing EventTempTargetChange")
rxBus.send(EventTempTargetChange())
}
}
}

View file

@ -33,13 +33,11 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.dana.comm.RecordTypes;
import info.nightscout.androidaps.data.NonOverlappingIntervals;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventCareportalEventChange;
import info.nightscout.androidaps.events.EventExtendedBolusChange;
import info.nightscout.androidaps.events.EventNewBG;
import info.nightscout.androidaps.events.EventProfileNeedsUpdate;
import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.events.EventReloadProfileSwitchData;
@ -54,9 +52,7 @@ import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData;
import info.nightscout.androidaps.plugins.general.openhumans.OpenHumansUploader;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightBolusID;
import info.nightscout.androidaps.plugins.pump.insight.database.InsightHistoryOffset;
@ -64,7 +60,6 @@ import info.nightscout.androidaps.plugins.pump.insight.database.InsightPumpID;
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.PercentageSplitter;
import info.nightscout.androidaps.utils.T;
/**
* This Helper contains all resource to provide a central DB management functionality. Only methods handling
@ -81,7 +76,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
@Inject OpenHumansUploader openHumansUploader;
public static final String DATABASE_NAME = "AndroidAPSDb";
public static final String DATABASE_BGREADINGS = "BgReadings";
public static final String DATABASE_TEMPORARYBASALS = "TemporaryBasals";
public static final String DATABASE_EXTENDEDBOLUSES = "ExtendedBoluses";
public static final String DATABASE_TEMPTARGETS = "TempTargets";
@ -101,10 +95,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final ScheduledExecutorService bgWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledBgPost = null;
private static final ScheduledExecutorService bgHistoryWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledBgHistoryPost = null;
private static long oldestBgHistoryChange = 0;
private static final ScheduledExecutorService tempBasalsWorker = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> scheduledTemBasalsPost = null;
@ -135,7 +125,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
try {
aapsLogger.info(LTag.DATABASE, "onCreate");
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
//TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
@ -167,7 +157,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
if (oldVersion < 7) {
aapsLogger.info(LTag.DATABASE, "onUpgrade");
TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true);
//TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
@ -217,7 +207,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public void resetDatabases() {
try {
TableUtils.dropTable(connectionSource, TempTarget.class, true);
TableUtils.dropTable(connectionSource, BgReading.class, true);
//TableUtils.dropTable(connectionSource, BgReading.class, true);
TableUtils.dropTable(connectionSource, DanaRHistoryRecord.class, true);
TableUtils.dropTable(connectionSource, DbRequest.class, true);
TableUtils.dropTable(connectionSource, TemporaryBasal.class, true);
@ -227,7 +217,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, TDD.class, true);
TableUtils.dropTable(connectionSource, OmnipodHistoryRecord.class, true);
TableUtils.createTableIfNotExists(connectionSource, TempTarget.class);
TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
//TableUtils.createTableIfNotExists(connectionSource, BgReading.class);
TableUtils.createTableIfNotExists(connectionSource, DanaRHistoryRecord.class);
TableUtils.createTableIfNotExists(connectionSource, DbRequest.class);
TableUtils.createTableIfNotExists(connectionSource, TemporaryBasal.class);
@ -241,7 +231,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
aapsLogger.error("Unhandled exception", e);
}
virtualPumpPlugin.setFakingStatus(true);
scheduleBgChange(null); // trigger refresh
scheduleTemporaryBasalChange();
scheduleExtendedBolusChange();
scheduleTemporaryTargetChange();
@ -326,10 +315,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return getDao(TempTarget.class);
}
private Dao<BgReading, Long> getDaoBgReadings() throws SQLException {
return getDao(BgReading.class);
}
private Dao<DanaRHistoryRecord, String> getDaoDanaRHistory() throws SQLException {
return getDao(DanaRHistoryRecord.class);
}
@ -384,144 +369,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
aapsLogger.debug(LTag.DATABASE, "Rounding " + date + " to " + rounded);
return rounded;
}
// ------------------- BgReading handling -----------------------
public boolean createIfNotExists(BgReading bgReading, String from) {
try {
bgReading.date = roundDateToSec(bgReading.date);
BgReading old = getDaoBgReadings().queryForId(bgReading.date);
if (old == null) {
getDaoBgReadings().create(bgReading);
openHumansUploader.enqueueBGReading(bgReading);
aapsLogger.debug(LTag.DATABASE, "BG: New record from: " + from + " " + bgReading.toString());
scheduleBgChange(bgReading);
return true;
}
if (!old.isEqual(bgReading)) {
aapsLogger.debug(LTag.DATABASE, "BG: Similiar found: " + old.toString());
old.copyFrom(bgReading);
getDaoBgReadings().update(old);
openHumansUploader.enqueueBGReading(old);
aapsLogger.debug(LTag.DATABASE, "BG: Updating record from: " + from + " New data: " + old.toString());
scheduleBgHistoryChange(old.date); // trigger cache invalidation
return false;
}
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return false;
}
public void update(BgReading bgReading) {
bgReading.date = roundDateToSec(bgReading.date);
try {
getDaoBgReadings().update(bgReading);
openHumansUploader.enqueueBGReading(bgReading);
aapsLogger.debug(LTag.DATABASE, "BG: Updating record from: "+ bgReading.toString());
scheduleBgHistoryChange(bgReading.date); // trigger cache invalidation
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
}
private void scheduleBgChange(@Nullable final BgReading bgReading) {
class PostRunnable implements Runnable {
public void run() {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg");
rxBus.send(new EventNewBG(bgReading));
scheduledBgPost = null;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledBgPost != null)
scheduledBgPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 1;
scheduledBgPost = bgWorker.schedule(task, sec, TimeUnit.SECONDS);
}
private void scheduleBgHistoryChange(@Nullable final long timestamp) {
class PostRunnable implements Runnable {
public void run() {
aapsLogger.debug(LTag.DATABASE, "Firing EventNewBg");
rxBus.send(new EventNewHistoryBgData(oldestBgHistoryChange));
scheduledBgHistoryPost = null;
oldestBgHistoryChange = 0;
}
}
// prepare task for execution in 1 sec
// cancel waiting task to prevent sending multiple posts
if (scheduledBgHistoryPost != null)
scheduledBgHistoryPost.cancel(false);
Runnable task = new PostRunnable();
final int sec = 3;
if (oldestBgHistoryChange == 0 || oldestBgHistoryChange > timestamp)
oldestBgHistoryChange = timestamp;
scheduledBgHistoryPost = bgHistoryWorker.schedule(task, sec, TimeUnit.SECONDS);
}
public List<BgReading> getBgreadingsDataFromTime(long mills, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills).and().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<BgReading> getBgreadingsDataFromTime(long start, long end, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.between("date", start, end).and().ge("value", 39).and().eq("isValid", true);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<>();
}
public List<BgReading> getAllBgreadingsDataFromTime(long mills, boolean ascending) {
try {
Dao<BgReading, Long> daoBgreadings = getDaoBgReadings();
List<BgReading> bgReadings;
QueryBuilder<BgReading, Long> queryBuilder = daoBgreadings.queryBuilder();
queryBuilder.orderBy("date", ascending);
Where where = queryBuilder.where();
where.ge("date", mills);
PreparedQuery<BgReading> preparedQuery = queryBuilder.prepare();
bgReadings = daoBgreadings.query(preparedQuery);
return bgReadings;
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return new ArrayList<BgReading>();
}
public List<BgReading> getAllBgReadings() {
try {
return getDaoBgReadings().queryForAll();
} catch (SQLException e) {
aapsLogger.error("Unhandled exception", e);
}
return Collections.emptyList();
}
// ------------------- TDD handling -----------------------
public void createOrUpdateTDD(TDD tdd) {
@ -1672,6 +1519,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
}
return Collections.emptyList();
}
@Nullable
private ProfileSwitch getLastProfileSwitchWithoutDuration() {
try {
@ -2010,7 +1858,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
return null;
}
// Copied from xDrip+
/*
TODO implement again for database branch // Copied from xDrip+
String calculateDirection(BgReading bgReading) {
// Rework to get bgreaings from internal DB and calculate on that base
@ -2056,7 +1905,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
// aapsLogger.error(LTag.GLUCOSE, "Direction set to: " + arrow);
return arrow;
}
*/
// ---------------- Open Humans Queue handling ---------------
public void clearOpenHumansQueue() {
@ -2109,8 +1958,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
public long getCountOfAllRows() {
try {
return getDaoBgReadings().countOf()
+ getDaoCareportalEvents().countOf()
return getDaoCareportalEvents().countOf()
+ getDaoExtendedBolus().countOf()
+ getDaoCareportalEvents().countOf()
+ getDaoProfileSwitch().countOf()

View file

@ -20,10 +20,6 @@ public class DatabaseHelperProvider implements DatabaseHelperInterface {
@Inject DatabaseHelperProvider() {
}
@NotNull @Override public List<BgReading> getAllBgreadingsDataFromTime(long mills, boolean ascending) {
return MainApp.getDbHelper().getAllBgreadingsDataFromTime(mills, ascending);
}
@Override public void createOrUpdate(@NotNull CareportalEvent careportalEvent) {
MainApp.getDbHelper().createOrUpdate(careportalEvent);
}

View file

@ -9,14 +9,16 @@ import info.nightscout.androidaps.core.di.CoreModule
import info.nightscout.androidaps.dana.di.DanaModule
import info.nightscout.androidaps.danar.di.DanaRModule
import info.nightscout.androidaps.danars.di.DanaRSModule
import info.nightscout.androidaps.database.DatabaseModule
import info.nightscout.androidaps.plugins.pump.common.dagger.RileyLinkModule
import info.nightscout.androidaps.plugins.pump.omnipod.dagger.OmnipodModule
import info.nightscout.androidaps.plugins.pump.omnipod.eros.dagger.OmnipodErosModule
import javax.inject.Singleton
@Singleton
@Component(
modules = [
AndroidInjectionModule::class,
DatabaseModule::class,
PluginsModule::class,
SkinsModule::class,
ActivitiesModule::class,
@ -30,7 +32,7 @@ import javax.inject.Singleton
WizardModule::class,
RileyLinkModule::class,
MedtronicModule::class,
OmnipodModule::class,
OmnipodErosModule::class,
APSModule::class,
PreferencesModule::class,
OverviewModule::class,
@ -41,6 +43,7 @@ import javax.inject.Singleton
DanaModule::class,
DanaRModule::class,
DanaRSModule::class,
WorkersModule::class,
OHUploaderModule::class
]
)

View file

@ -17,6 +17,8 @@ import info.nightscout.androidaps.plugins.general.nsclient.UploadQueue
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.CommandQueue
import info.nightscout.androidaps.utils.androidNotification.NotificationHolder
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.rx.DefaultAapsSchedulers
import info.nightscout.androidaps.utils.storage.FileStorage
import info.nightscout.androidaps.utils.storage.Storage
import javax.inject.Singleton
@ -46,6 +48,10 @@ open class AppModule {
return FileStorage()
}
@Provides
@Singleton
internal fun provideSchedulers(): AapsSchedulers = DefaultAapsSchedulers()
@Module
interface AppBindings {

View file

@ -2,11 +2,9 @@ package info.nightscout.androidaps.dependencyInjection
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.db.DatabaseHelper
import info.nightscout.androidaps.plugins.general.food.FoodService
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.treatments.TreatmentService
import info.nightscout.androidaps.utils.wizard.BolusWizard
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry

View file

@ -36,7 +36,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyL
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightFragment
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicFragment
import info.nightscout.androidaps.plugins.pump.medtronic.dialog.RileyLinkStatusDeviceMedtronic
import info.nightscout.androidaps.plugins.pump.omnipod.ui.OmnipodOverviewFragment
import info.nightscout.androidaps.plugins.pump.omnipod.eros.ui.OmnipodOverviewFragment
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
import info.nightscout.androidaps.plugins.source.BGSourceFragment
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment

View file

@ -42,7 +42,7 @@ import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
@ -160,7 +160,7 @@ abstract class PluginsModule {
@PumpDriver
@IntoMap
@IntKey(155)
abstract fun bindOmnipodPumpPlugin(plugin: OmnipodPumpPlugin): PluginBase
abstract fun bindOmnipodPumpPlugin(plugin: OmnipodErosPumpPlugin): PluginBase
@Binds
@NotNSClient

View file

@ -10,9 +10,8 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.Riley
import info.nightscout.androidaps.plugins.pump.insight.InsightAlertService
import info.nightscout.androidaps.plugins.pump.insight.connection_service.InsightConnectionService
import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService
import info.nightscout.androidaps.plugins.pump.omnipod.rileylink.service.RileyLinkOmnipodService
import info.nightscout.androidaps.plugins.pump.omnipod.eros.rileylink.service.RileyLinkOmnipodService
import info.nightscout.androidaps.services.AlarmSoundService
import info.nightscout.androidaps.services.DataService
import info.nightscout.androidaps.services.LocationService
@Module
@ -20,7 +19,6 @@ import info.nightscout.androidaps.services.LocationService
abstract class ServicesModule {
@ContributesAndroidInjector abstract fun contributesAlarmSoundService(): AlarmSoundService
@ContributesAndroidInjector abstract fun contributesDataService(): DataService
@ContributesAndroidInjector abstract fun contributesDismissNotificationService(): DismissNotificationService
@ContributesAndroidInjector abstract fun contributesDummyService(): DummyService
@ContributesAndroidInjector abstract fun contributesLocationService(): LocationService

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.dependencyInjection
import dagger.Module
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.nsclient.NSClientWorker
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
import info.nightscout.androidaps.plugins.source.*
@Module
@Suppress("unused")
abstract class WorkersModule {
@ContributesAndroidInjector abstract fun contributesXdripWorker(): XdripPlugin.XdripWorker
@ContributesAndroidInjector abstract fun contributesDexcomWorker(): DexcomPlugin.DexcomWorker
@ContributesAndroidInjector abstract fun contributesMM640gWorker(): MM640gPlugin.MM640gWorker
@ContributesAndroidInjector abstract fun contributesGlimpWorker(): GlimpPlugin.GlimpWorker
@ContributesAndroidInjector abstract fun contributesPoctechWorker(): PoctechPlugin.PoctechWorker
@ContributesAndroidInjector abstract fun contributesTomatoWorker(): TomatoPlugin.TomatoWorker
@ContributesAndroidInjector abstract fun contributesEversenseWorker(): EversensePlugin.EversenseWorker
@ContributesAndroidInjector abstract fun contributesNSClientSourceWorker(): NSClientSourcePlugin.NSClientSourceWorker
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): NSProfilePlugin.NSProfileWorker
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorWorker(): SmsCommunicatorPlugin.SmsCommunicatorWorker
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientWorker
}

View file

@ -13,13 +13,13 @@ import android.widget.AdapterView.OnItemSelectedListener
import android.widget.ArrayAdapter
import android.widget.CompoundButton
import androidx.fragment.app.FragmentManager
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.DialogWizardBinding
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.ProfileFunction
@ -36,9 +36,10 @@ import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.valueToUnits
import info.nightscout.androidaps.utils.wizard.BolusWizard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import java.text.DecimalFormat
import java.util.*
@ -47,7 +48,9 @@ import kotlin.math.abs
class WizardDialog : DaggerDialogFragment() {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var constraintChecker: ConstraintChecker
@Inject lateinit var mainApp: MainApp
@Inject lateinit var sp: SP
@ -188,10 +191,10 @@ class WizardDialog : DaggerDialogFragment() {
// bus
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
activity?.runOnUiThread { calculateInsulin() }
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
)
}
@ -232,6 +235,10 @@ class WizardDialog : DaggerDialogFragment() {
binding.cobcheckbox.isChecked = sp.getBoolean(R.string.key_wizard_include_cob, false)
}
private fun valueToUnitsToString(value: Double, units: String): String =
if (units == Constants.MGDL) DecimalFormatter.to0Decimal(value)
else DecimalFormatter.to1Decimal(value * Constants.MGDL_TO_MMOLL)
private fun initDialog() {
val profile = profileFunction.getProfile()
val profileStore = activePlugin.activeProfileInterface.profile
@ -242,8 +249,7 @@ class WizardDialog : DaggerDialogFragment() {
return
}
val profileList: ArrayList<CharSequence>
profileList = profileStore.getProfileList()
val profileList: ArrayList<CharSequence> = profileStore.getProfileList()
profileList.add(0, resourceHelper.gs(R.string.active))
context?.let { context ->
val adapter = ArrayAdapter(context, R.layout.spinner_centered, profileList)
@ -331,7 +337,7 @@ class WizardDialog : DaggerDialogFragment() {
binding.notes.text.toString(), carbTime)
wizard?.let { wizard ->
binding.bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), BgReading().value(Profile.toMgdl(bg, profileFunction.getUnits())).valueToUnitsToString(profileFunction.getUnits()), wizard.sens)
binding.bg.text = String.format(resourceHelper.gs(R.string.format_bg_isf), valueToUnitsToString(Profile.toMgdl(bg, profileFunction.getUnits()), profileFunction.getUnits()), wizard.sens)
binding.bginsulin.text = resourceHelper.gs(R.string.formatinsulinunits, wizard.insulinFromBG)
binding.carbs.text = String.format(resourceHelper.gs(R.string.format_carbs_ic), carbs.toDouble(), wizard.ic)

View file

@ -1,5 +1,5 @@
package info.nightscout.androidaps.events
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.database.entities.GlucoseValue
class EventNewBG(val bgReading: BgReading?) : EventLoop()
class EventNewBG(val glucoseValue: GlucoseValue?) : EventLoop()

View file

@ -32,10 +32,9 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -46,6 +45,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction
@ -148,7 +148,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
binding.bggraph.gridLabelRenderer?.reloadStyles()
binding.bggraph.gridLabelRenderer?.labelVerticalWidth = axisWidth
overviewMenus.setupChartMenu(binding.overviewChartMenuButton)
overviewMenus.setupChartMenu(binding.chartMenuButton)
prepareGraphsIfNeeded(overviewMenus.setting.size)
savedInstanceState?.let { bundle ->
rangeToDisplay = bundle.getInt("rangeToDisplay", 0)
@ -173,7 +173,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
super.onResume()
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({
// catch only events from iobCobCalculatorPluginHistory
if (it.cause is EventCustomCalculationFinished) {
@ -183,7 +183,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
)
disposable.add(rxBus
.toObservable(EventAutosensBgLoaded::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({
// catch only events from iobCobCalculatorPluginHistory
if (it.cause is EventCustomCalculationFinished) {
@ -193,12 +193,12 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
)
disposable.add(rxBus
.toObservable(EventIobCalculationProgress::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({ binding.overviewIobcalculationprogess.text = it.progress }, fabricPrivacy::logException)
)
disposable.add(rxBus
.toObservable(EventRefreshOverview::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
if (it.now) {
updateGUI("EventRefreshOverview", bgOnly = false)
@ -308,7 +308,6 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
// **** BG ****
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
// add target line
graphData.addTargetLine(fromTime, toTime, profile, null)
@ -334,24 +333,27 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
var useDevForScale = false
var useRatioForScale = false
var useDSForScale = false
var useIAForScale = false
var useBGIForScale = false
var useABSForScale = false
when {
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
}
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal])
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, toTime, useIAForScale, 0.8)
var alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
var alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, toTime, useABSForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, toTime, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, toTime, useCobForScale, if (useCobForScale) 1.0 else 0.5)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, toTime, useDevForScale, 1.0, alignDevBgiScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, toTime, useRatioForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, toTime, useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, toTime, useDSForScale, 1.0)
// set manual x bounds to have nice steps

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.historyBrowser
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
@ -12,6 +13,7 @@ import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAverage
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton
@ -20,6 +22,7 @@ import javax.inject.Singleton
class IobCobCalculatorPluginHistory @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
aapsSchedulers: AapsSchedulers,
rxBus: RxBusWrapper,
sp: SP,
resourceHelper: ResourceHelper,
@ -30,9 +33,10 @@ class IobCobCalculatorPluginHistory @Inject constructor(
sensitivityAAPSPlugin: SensitivityAAPSPlugin,
sensitivityWeightedAveragePlugin: SensitivityWeightedAveragePlugin,
fabricPrivacy: FabricPrivacy,
dateUtil: DateUtil
) : IobCobCalculatorPlugin(injector, aapsLogger, rxBus, sp, resourceHelper, profileFunction,
activePlugin, treatmentsPluginHistory, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil) {
dateUtil: DateUtil,
repository: AppRepository
) : IobCobCalculatorPlugin(injector, aapsLogger, aapsSchedulers, rxBus, sp, resourceHelper, profileFunction,
activePlugin, treatmentsPluginHistory, sensitivityOref1Plugin, sensitivityAAPSPlugin, sensitivityWeightedAveragePlugin, fabricPrivacy, dateUtil, repository) {
override fun onStart() { // do not attach to rxbus
}

View file

@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton
@ -21,6 +22,7 @@ import javax.inject.Singleton
class TreatmentsPluginHistory @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
aapsSchedulers: AapsSchedulers,
rxBus: RxBusWrapper,
resourceHelper: ResourceHelper,
context: Context,
@ -31,7 +33,7 @@ class TreatmentsPluginHistory @Inject constructor(
fabricPrivacy: FabricPrivacy,
dateUtil: DateUtil,
uploadQueue: UploadQueue
) : TreatmentsPlugin(injector, aapsLogger, rxBus, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue) {
) : TreatmentsPlugin(injector, aapsLogger, rxBus, aapsSchedulers, resourceHelper, context, sp, profileFunction, activePlugin, nsUpload, fabricPrivacy, dateUtil, uploadQueue) {
init {
onStart()

View file

@ -17,13 +17,15 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject
class LoopFragment : DaggerFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper
@ -59,18 +61,18 @@ class LoopFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventLoopUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
updateGUI()
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventLoopSetLastRunGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
clearGUI()
binding.lastrun.text = it.text
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
updateGUI()
sp.putBoolean(R.string.key_objectiveuseloop, true)

View file

@ -30,7 +30,7 @@ import info.nightscout.androidaps.activities.ErrorHelperActivity;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
@ -72,15 +72,16 @@ import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.HardLimits;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
@Singleton
public class LoopPlugin extends PluginBase implements LoopInterface {
private final HasAndroidInjector injector;
private final SP sp;
private final RxBusWrapper rxBus;
private final AapsSchedulers aapsSchedulers;
private final ConstraintChecker constraintChecker;
private final ResourceHelper resourceHelper;
private final ProfileFunction profileFunction;
@ -123,6 +124,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
public LoopPlugin(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
AapsSchedulers aapsSchedulers,
RxBusWrapper rxBus,
SP sp,
Config config,
@ -153,6 +155,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
aapsLogger, resourceHelper, injector
);
this.injector = injector;
this.aapsSchedulers = aapsSchedulers;
this.sp = sp;
this.rxBus = rxBus;
this.constraintChecker = constraintChecker;
@ -181,7 +184,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
super.onStart();
disposable.add(rxBus
.toObservable(EventTempTargetChange.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> invoke("EventTempTargetChange", true), fabricPrivacy::logException)
);
/*
@ -193,19 +196,19 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
*/
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
// Autosens calculation not triggered by a new BG
if (!(event.getCause() instanceof EventNewBG)) return;
BgReading bgReading = iobCobCalculatorPlugin.actualBg();
GlucoseValue glucoseValue = iobCobCalculatorPlugin.actualBg();
// BG outdated
if (bgReading == null) return;
if (glucoseValue == null) return;
// already looped with that value
if (bgReading.date <= lastBgTriggeredRun) return;
if (glucoseValue.getTimestamp() <= lastBgTriggeredRun) return;
lastBgTriggeredRun = bgReading.date;
invoke("AutosenseCalculation for " + bgReading, true);
lastBgTriggeredRun = glucoseValue.getTimestamp();
invoke("AutosenseCalculation for " + glucoseValue, true);
}, fabricPrivacy::logException)
);
}
@ -389,30 +392,30 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
// Prepare for pumps using % basals
if (pump.getPumpDescription().tempBasalStyle == PumpDescription.PERCENT && allowPercentage()) {
result.usePercent = true;
result.setUsePercent(true);
}
result.percent = (int) (result.rate / profile.getBasal() * 100);
result.setPercent((int) (result.getRate() / profile.getBasal() * 100));
// check rate for constraints
final APSResult resultAfterConstraints = result.newAndClone(injector);
resultAfterConstraints.rateConstraint = new Constraint<>(resultAfterConstraints.rate);
resultAfterConstraints.rate = constraintChecker.applyBasalConstraints(resultAfterConstraints.rateConstraint, profile).value();
resultAfterConstraints.setRateConstraint(new Constraint<>(resultAfterConstraints.getRate()));
resultAfterConstraints.setRate(constraintChecker.applyBasalConstraints(resultAfterConstraints.getRateConstraint(), profile).value());
resultAfterConstraints.percentConstraint = new Constraint<>(resultAfterConstraints.percent);
resultAfterConstraints.percent = constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.percentConstraint, profile).value();
resultAfterConstraints.setPercentConstraint(new Constraint<>(resultAfterConstraints.getPercent()));
resultAfterConstraints.setPercent(constraintChecker.applyBasalPercentConstraints(resultAfterConstraints.getPercentConstraint(), profile).value());
resultAfterConstraints.smbConstraint = new Constraint<>(resultAfterConstraints.smb);
resultAfterConstraints.smb = constraintChecker.applyBolusConstraints(resultAfterConstraints.smbConstraint).value();
resultAfterConstraints.setSmbConstraint(new Constraint<>(resultAfterConstraints.getSmb()));
resultAfterConstraints.setSmb(constraintChecker.applyBolusConstraints(resultAfterConstraints.getSmbConstraint()).value());
// safety check for multiple SMBs
long lastBolusTime = treatmentsPlugin.getLastBolusTime();
if (lastBolusTime != 0 && lastBolusTime + T.mins(3).msecs() > System.currentTimeMillis()) {
getAapsLogger().debug(LTag.APS, "SMB requested but still in 3 min interval");
resultAfterConstraints.smb = 0;
resultAfterConstraints.setSmb(0);
}
if (lastRun != null && lastRun.getConstraintsProcessed() != null) {
prevCarbsreq = lastRun.getConstraintsProcessed().carbsReq;
prevCarbsreq = lastRun.getConstraintsProcessed().getCarbsReq();
}
if (lastRun == null) lastRun = new LastRun();
@ -446,7 +449,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
if (closedLoopEnabled.value()) {
if (allowNotification) {
if (resultAfterConstraints.isCarbsRequired()
&& resultAfterConstraints.carbsReq >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0)
&& resultAfterConstraints.getCarbsReq() >= sp.getInt(R.string.key_smb_enable_carbs_suggestions_threshold, 0)
&& carbsSuggestionsSuspendedUntil < System.currentTimeMillis() && !treatmentTimethreshold(-15)) {
if (sp.getBoolean(R.string.key_enable_carbs_required_alert_local, true) && !sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
@ -516,9 +519,9 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
&& !commandQueue.isRunning(Command.CommandType.BOLUS)) {
final PumpEnactResult waiting = new PumpEnactResult(getInjector());
waiting.queued = true;
if (resultAfterConstraints.tempBasalRequested)
if (resultAfterConstraints.getTempBasalRequested())
lastRun.setTbrSetByPump(waiting);
if (resultAfterConstraints.bolusRequested)
if (resultAfterConstraints.getBolusRequested())
lastRun.setSmbSetByPump(waiting);
rxBus.send(new EventLoopUpdateGui());
fabricPrivacy.logCustom("APSRequest");
@ -650,7 +653,7 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
private void applyTBRRequest(APSResult request, Profile profile, Callback callback) {
if (!request.tempBasalRequested) {
if (!request.getTempBasalRequested()) {
if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).enacted(false).success(true).comment(resourceHelper.gs(R.string.nochangerequested))).run();
}
@ -679,48 +682,48 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
long now = System.currentTimeMillis();
TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(now);
if (request.usePercent && allowPercentage()) {
if (request.percent == 100 && request.duration == 0) {
if (request.getUsePercent() && allowPercentage()) {
if (request.getPercent() == 100 && request.getDuration() == 0) {
if (activeTemp != null) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
commandQueue.cancelTempBasal(false, callback);
} else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).percent(request.percent).duration(0)
callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent()).duration(0)
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
}
}
} else if (activeTemp != null
&& activeTemp.getPlannedRemainingMinutes() > 5
&& request.duration - activeTemp.getPlannedRemainingMinutes() < 30
&& request.percent == activeTemp.percentRate) {
&& request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
&& request.getPercent() == activeTemp.percentRate) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).percent(request.percent)
callback.result(new PumpEnactResult(getInjector()).percent(request.getPercent())
.enacted(false).success(true).duration(activeTemp.getPlannedRemainingMinutes())
.comment(resourceHelper.gs(R.string.let_temp_basal_run))).run();
}
} else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: tempBasalPercent()");
commandQueue.tempBasalPercent(request.percent, request.duration, false, profile, callback);
commandQueue.tempBasalPercent(request.getPercent(), request.getDuration(), false, profile, callback);
}
} else {
if ((request.rate == 0 && request.duration == 0) || Math.abs(request.rate - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
if ((request.getRate() == 0 && request.getDuration() == 0) || Math.abs(request.getRate() - pump.getBaseBasalRate()) < pump.getPumpDescription().basalStep) {
if (activeTemp != null) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: cancelTempBasal()");
commandQueue.cancelTempBasal(false, callback);
} else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).absolute(request.rate).duration(0)
callback.result(new PumpEnactResult(getInjector()).absolute(request.getRate()).duration(0)
.enacted(false).success(true).comment(resourceHelper.gs(R.string.basal_set_correctly))).run();
}
}
} else if (activeTemp != null
&& activeTemp.getPlannedRemainingMinutes() > 5
&& request.duration - activeTemp.getPlannedRemainingMinutes() < 30
&& Math.abs(request.rate - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
&& request.getDuration() - activeTemp.getPlannedRemainingMinutes() < 30
&& Math.abs(request.getRate() - activeTemp.tempBasalConvertedToAbsolute(now, profile)) < pump.getPumpDescription().basalStep) {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: Temp basal set correctly");
if (callback != null) {
callback.result(new PumpEnactResult(getInjector()).absolute(activeTemp.tempBasalConvertedToAbsolute(now, profile))
@ -729,13 +732,13 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
}
} else {
getAapsLogger().debug(LTag.APS, "applyAPSRequest: setTempBasalAbsolute()");
commandQueue.tempBasalAbsolute(request.rate, request.duration, false, profile, callback);
commandQueue.tempBasalAbsolute(request.getRate(), request.getDuration(), false, profile, callback);
}
}
}
private void applySMBRequest(APSResult request, Callback callback) {
if (!request.bolusRequested) {
if (!request.getBolusRequested()) {
return;
}
@ -774,10 +777,10 @@ public class LoopPlugin extends PluginBase implements LoopInterface {
DetailedBolusInfo detailedBolusInfo = new DetailedBolusInfo();
detailedBolusInfo.lastKnownBolusTime = treatmentsPlugin.getLastBolusTime();
detailedBolusInfo.eventType = CareportalEvent.CORRECTIONBOLUS;
detailedBolusInfo.insulin = request.smb;
detailedBolusInfo.insulin = request.getSmb();
detailedBolusInfo.isSMB = true;
detailedBolusInfo.source = Source.USER;
detailedBolusInfo.deliverAt = request.deliverAt;
detailedBolusInfo.deliverAt = request.getDeliverAt();
getAapsLogger().debug(LTag.APS, "applyAPSRequest: bolus()");
commandQueue.bolus(detailedBolusInfo, callback);
}

View file

@ -1,77 +0,0 @@
package info.nightscout.androidaps.plugins.aps.openAPSAMA;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.javascript.NativeObject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.utils.DateUtil;
public class DetermineBasalResultAMA extends APSResult {
private AAPSLogger aapsLogger;
private double eventualBG;
private double snoozeBG;
DetermineBasalResultAMA(HasAndroidInjector injector, NativeObject result, JSONObject j) {
this(injector);
date = DateUtil.now();
json = j;
if (result.containsKey("error")) {
reason = result.get("error").toString();
tempBasalRequested = false;
rate = -1;
duration = -1;
} else {
reason = result.get("reason").toString();
if (result.containsKey("eventualBG")) eventualBG = (Double) result.get("eventualBG");
if (result.containsKey("snoozeBG")) snoozeBG = (Double) result.get("snoozeBG");
if (result.containsKey("rate")) {
rate = (Double) result.get("rate");
if (rate < 0d) rate = 0d;
tempBasalRequested = true;
} else {
rate = -1;
tempBasalRequested = false;
}
if (result.containsKey("duration")) {
duration = ((Double) result.get("duration")).intValue();
//changeRequested as above
} else {
duration = -1;
tempBasalRequested = false;
}
}
bolusRequested = false;
}
private DetermineBasalResultAMA(HasAndroidInjector injector) {
super(injector);
hasPredictions = true;
}
@Override
public DetermineBasalResultAMA newAndClone(HasAndroidInjector injector) {
DetermineBasalResultAMA newResult = new DetermineBasalResultAMA(injector);
doClone(newResult);
newResult.eventualBG = eventualBG;
newResult.snoozeBG = snoozeBG;
return newResult;
}
@Override
public JSONObject json() {
try {
JSONObject ret = new JSONObject(this.json.toString());
return ret;
} catch (JSONException e) {
aapsLogger.error(LTag.APS, "Unhandled exception", e);
}
return null;
}
}

View file

@ -0,0 +1,67 @@
package info.nightscout.androidaps.plugins.aps.openAPSAMA
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONException
import org.json.JSONObject
import org.mozilla.javascript.NativeObject
class DetermineBasalResultAMA private constructor(injector: HasAndroidInjector) : APSResult(injector) {
private var eventualBG = 0.0
private var snoozeBG = 0.0
internal constructor(injector: HasAndroidInjector, result: NativeObject, j: JSONObject) : this(injector) {
date = DateUtil.now()
json = j
if (result.containsKey("error")) {
reason = result["error"].toString()
tempBasalRequested = false
rate = (-1).toDouble()
duration = -1
} else {
reason = result["reason"].toString()
if (result.containsKey("eventualBG")) eventualBG = result["eventualBG"] as Double
if (result.containsKey("snoozeBG")) snoozeBG = result["snoozeBG"] as Double
if (result.containsKey("rate")) {
rate = result["rate"] as Double
if (rate < 0.0) rate = 0.0
tempBasalRequested = true
} else {
rate = (-1).toDouble()
tempBasalRequested = false
}
if (result.containsKey("duration")) {
duration = (result["duration"] as Double).toInt()
//changeRequested as above
} else {
duration = -1
tempBasalRequested = false
}
}
bolusRequested = false
}
override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultAMA {
val newResult = DetermineBasalResultAMA(injector)
doClone(newResult)
newResult.eventualBG = eventualBG
newResult.snoozeBG = snoozeBG
return newResult
}
override fun json(): JSONObject? {
try {
return JSONObject(json.toString())
} catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Unhandled exception", e)
}
return null
}
init {
hasPredictions = true
}
}

View file

@ -18,7 +18,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.JSONFormatter
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import org.json.JSONArray
import org.json.JSONException
@ -29,6 +29,7 @@ class OpenAPSAMAFragment : DaggerFragment() {
private var disposable: CompositeDisposable = CompositeDisposable()
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@ -61,16 +62,16 @@ class OpenAPSAMAFragment : DaggerFragment() {
disposable += rxBus
.toObservable(EventOpenAPSUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
updateGUI()
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventOpenAPSUpdateResultGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
updateResultGUI(it.text)
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
updateGUI()
}

View file

@ -18,20 +18,20 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
@ -238,15 +238,15 @@ public class OpenAPSAMAPlugin extends PluginBase implements APSInterface {
lastAPSResult = null;
lastAPSRun = 0;
} else {
if (determineBasalResultAMA.rate == 0d && determineBasalResultAMA.duration == 0 && !treatmentsPlugin.isTempBasalInProgress())
determineBasalResultAMA.tempBasalRequested = false;
if (determineBasalResultAMA.getRate() == 0d && determineBasalResultAMA.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
determineBasalResultAMA.setTempBasalRequested(false);
determineBasalResultAMA.iob = iobArray[0];
determineBasalResultAMA.setIob(iobArray[0]);
long now = System.currentTimeMillis();
try {
determineBasalResultAMA.json.put("timestamp", DateUtil.toISOString(now));
determineBasalResultAMA.getJson().put("timestamp", DateUtil.toISOString(now));
} catch (JSONException e) {
aapsLogger.error(LTag.APS, "Unhandled exception", e);
}

View file

@ -1,97 +0,0 @@
package info.nightscout.androidaps.plugins.aps.openAPSSMB;
import org.json.JSONException;
import org.json.JSONObject;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
public class DetermineBasalResultSMB extends APSResult {
@Inject SP sp;
private double eventualBG;
private double snoozeBG;
private DetermineBasalResultSMB(HasAndroidInjector injector) {
super(injector);
hasPredictions = true;
}
DetermineBasalResultSMB(HasAndroidInjector injector, JSONObject result) {
this(injector);
date = DateUtil.now();
json = result;
try {
if (result.has("error")) {
reason = result.getString("error");
return;
}
reason = result.getString("reason");
if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG");
if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG");
//if (result.has("insulinReq")) insulinReq = result.getDouble("insulinReq");
if (result.has("carbsReq")) carbsReq = result.getInt("carbsReq");
if (result.has("carbsReqWithin")) carbsReqWithin = result.getInt("carbsReqWithin");
if (result.has("rate") && result.has("duration")) {
tempBasalRequested = true;
rate = result.getDouble("rate");
if (rate < 0d) rate = 0d;
duration = result.getInt("duration");
} else {
rate = -1;
duration = -1;
}
if (result.has("units")) {
bolusRequested = true;
smb = result.getDouble("units");
} else {
smb = 0d;
}
if (result.has("targetBG")) {
targetBG = result.getDouble("targetBG");
}
if (result.has("deliverAt")) {
String date = result.getString("deliverAt");
try {
deliverAt = DateUtil.fromISODateString(date).getTime();
} catch (Exception e) {
aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: " + date, e);
}
}
} catch (JSONException e) {
aapsLogger.error(LTag.APS, "Error parsing determine-basal result JSON", e);
}
}
@Override
public DetermineBasalResultSMB newAndClone(HasAndroidInjector injector) {
DetermineBasalResultSMB newResult = new DetermineBasalResultSMB(injector);
doClone(newResult);
newResult.eventualBG = eventualBG;
newResult.snoozeBG = snoozeBG;
return newResult;
}
@Override
public JSONObject json() {
try {
return new JSONObject(this.json.toString());
} catch (JSONException e) {
aapsLogger.error(LTag.APS, "Error converting determine-basal result to JSON", e);
}
return null;
}
}

View file

@ -0,0 +1,80 @@
package info.nightscout.androidaps.plugins.aps.openAPSSMB
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.utils.DateUtil
import org.json.JSONException
import org.json.JSONObject
class DetermineBasalResultSMB private constructor(injector: HasAndroidInjector) : APSResult(injector) {
private var eventualBG = 0.0
private var snoozeBG = 0.0
internal constructor(injector: HasAndroidInjector, result: JSONObject) : this(injector) {
date = DateUtil.now()
json = result
try {
if (result.has("error")) {
reason = result.getString("error")
return
}
reason = result.getString("reason")
if (result.has("eventualBG")) eventualBG = result.getDouble("eventualBG")
if (result.has("snoozeBG")) snoozeBG = result.getDouble("snoozeBG")
//if (result.has("insulinReq")) insulinReq = result.getDouble("insulinReq");
if (result.has("carbsReq")) carbsReq = result.getInt("carbsReq")
if (result.has("carbsReqWithin")) carbsReqWithin = result.getInt("carbsReqWithin")
if (result.has("rate") && result.has("duration")) {
tempBasalRequested = true
rate = result.getDouble("rate")
if (rate < 0.0) rate = 0.0
duration = result.getInt("duration")
} else {
rate = (-1).toDouble()
duration = -1
}
if (result.has("units")) {
bolusRequested = true
smb = result.getDouble("units")
} else {
smb = 0.0
}
if (result.has("targetBG")) {
targetBG = result.getDouble("targetBG")
}
if (result.has("deliverAt")) {
val date = result.getString("deliverAt")
try {
deliverAt = DateUtil.fromISODateString(date).time
} catch (e: Exception) {
aapsLogger.error(LTag.APS, "Error parsing 'deliverAt' date: $date", e)
}
}
} catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Error parsing determine-basal result JSON", e)
}
}
override fun newAndClone(injector: HasAndroidInjector): DetermineBasalResultSMB {
val newResult = DetermineBasalResultSMB(injector)
doClone(newResult)
newResult.eventualBG = eventualBG
newResult.snoozeBG = snoozeBG
return newResult
}
override fun json(): JSONObject? {
try {
return JSONObject(json.toString())
} catch (e: JSONException) {
aapsLogger.error(LTag.APS, "Error converting determine-basal result to JSON", e)
}
return null
}
init {
hasPredictions = true
}
}

View file

@ -19,16 +19,18 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.JSONFormatter
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import org.json.JSONArray
import org.json.JSONException
import javax.inject.Inject
class OpenAPSSMBFragment : DaggerFragment() {
private var disposable: CompositeDisposable = CompositeDisposable()
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@ -60,16 +62,16 @@ class OpenAPSSMBFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventOpenAPSUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
updateGUI()
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventOpenAPSUpdateResultGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
updateResultGUI(it.text)
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
updateGUI()
}

View file

@ -24,20 +24,20 @@ import info.nightscout.androidaps.interfaces.ConstraintsInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.FabricPrivacy;
@ -291,18 +291,18 @@ public class OpenAPSSMBPlugin extends PluginBase implements APSInterface, Constr
} else {
// TODO still needed with oref1?
// Fix bug determine basal
if (determineBasalResultSMB.rate == 0d && determineBasalResultSMB.duration == 0 && !treatmentsPlugin.isTempBasalInProgress())
determineBasalResultSMB.tempBasalRequested = false;
if (determineBasalResultSMB.getRate() == 0d && determineBasalResultSMB.getDuration() == 0 && !treatmentsPlugin.isTempBasalInProgress())
determineBasalResultSMB.setTempBasalRequested(false);
determineBasalResultSMB.iob = iobArray[0];
determineBasalResultSMB.setIob(iobArray[0]);
try {
determineBasalResultSMB.json.put("timestamp", DateUtil.toISOString(now));
determineBasalResultSMB.getJson().put("timestamp", DateUtil.toISOString(now));
} catch (JSONException e) {
getAapsLogger().error(LTag.APS, "Unhandled exception", e);
}
determineBasalResultSMB.inputConstraints = inputConstraints;
determineBasalResultSMB.setInputConstraints(inputConstraints);
lastDetermineBasalAdapterSMBJS = determineBasalAdapterSMBJS;
lastAPSResult = determineBasalResultSMB;

View file

@ -22,13 +22,14 @@ import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import java.util.*
import javax.inject.Inject
class ConfigBuilderFragment : DaggerFragment() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@ -77,10 +78,10 @@ class ConfigBuilderFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventConfigBuilderUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
for (pluginViewHolder in pluginViewHolders) pluginViewHolder.update()
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
updateGUI()
}

View file

@ -35,8 +35,8 @@ import info.nightscout.androidaps.utils.SntpClient
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject
@ -44,6 +44,7 @@ class ObjectivesFragment : DaggerFragment() {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var sp: SP
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@ -70,11 +71,8 @@ class ObjectivesFragment : DaggerFragment() {
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
_binding = ObjectivesFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
ObjectivesFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -95,11 +93,10 @@ class ObjectivesFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventObjectivesUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
binding.recyclerview.adapter?.notifyDataSetChanged()
}, { fabricPrivacy.logException(it) }
)
}, fabricPrivacy::logException)
}
@Synchronized

View file

@ -8,6 +8,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.Config
@ -25,7 +26,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.actions.defs.CustomAction
import info.nightscout.androidaps.plugins.general.overview.StatusLightHandler
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.FabricPrivacy
@ -35,19 +36,18 @@ import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.ui.SingleClickButton
import info.nightscout.androidaps.utils.ui.UIRunnable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.actions_fragment.*
import kotlinx.android.synthetic.main.careportal_stats_fragment.*
import java.util.*
import javax.inject.Inject
class ActionsFragment : DaggerFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP
@Inject lateinit var profileFunction: ProfileFunction
@ -70,6 +70,29 @@ class ActionsFragment : DaggerFragment() {
private var smallHeight = false
private lateinit var dm: DisplayMetrics
private var buttonsLayout: LinearLayout? = null
private var profileSwitch: SingleClickButton? = null
private var tempTarget: SingleClickButton? = null
private var extendedBolus: SingleClickButton? = null
private var extendedBolusCancel: SingleClickButton? = null
private var setTempBasal: SingleClickButton? = null
private var cancelTempBasal: SingleClickButton? = null
private var fill: SingleClickButton? = null
private var historyBrowser: SingleClickButton? = null
private var tddStats: SingleClickButton? = null
private var pumpBatteryChange: SingleClickButton? = null
private var cannulaAge: TextView? = null
private var insulinAge: TextView? = null
private var reservoirLevel: TextView? = null
private var sensorAge: TextView? = null
private var sensorLevel: TextView? = null
private var pbAge: TextView? = null
private var batteryLevel: TextView? = null
private var sensorLevelLabel: TextView? = null
private var insulinLevelLabel: TextView? = null
private var pbLevelLabel: TextView? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
//check screen width
@ -88,13 +111,36 @@ class ActionsFragment : DaggerFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
actions_profileswitch.setOnClickListener {
buttonsLayout = view.findViewById(R.id.action_buttons_layout)
profileSwitch = view.findViewById(R.id.actions_profileswitch)
tempTarget = view.findViewById(R.id.actions_temptarget)
extendedBolus = view.findViewById(R.id.actions_extendedbolus)
extendedBolusCancel = view.findViewById(R.id.actions_extendedbolus_cancel)
setTempBasal = view.findViewById(R.id.actions_settempbasal)
cancelTempBasal = view.findViewById(R.id.actions_canceltempbasal)
fill = view.findViewById(R.id.actions_fill)
historyBrowser = view.findViewById(R.id.actions_historybrowser)
tddStats = view.findViewById(R.id.actions_tddstats)
pumpBatteryChange = view.findViewById(R.id.actions_pumpbatterychange)
cannulaAge = view.findViewById(R.id.cannula_age)
insulinAge = view.findViewById(R.id.insulin_age)
reservoirLevel = view.findViewById(R.id.reservoir_level)
sensorAge = view.findViewById(R.id.sensor_age)
sensorLevel = view.findViewById(R.id.sensor_level)
pbAge = view.findViewById(R.id.pb_age)
batteryLevel = view.findViewById(R.id.battery_level)
sensorLevelLabel = view.findViewById(R.id.sensor_level_label)
insulinLevelLabel = view.findViewById(R.id.insulin_level_label)
pbLevelLabel = view.findViewById(R.id.pb_level_label)
profileSwitch?.setOnClickListener {
ProfileSwitchDialog().show(childFragmentManager, "Actions")
}
actions_temptarget.setOnClickListener {
tempTarget?.setOnClickListener {
TempTargetDialog().show(childFragmentManager, "Actions")
}
actions_extendedbolus.setOnClickListener {
extendedBolus?.setOnClickListener {
activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), resourceHelper.gs(R.string.ebstopsloop),
@ -104,7 +150,7 @@ class ActionsFragment : DaggerFragment() {
})
}
}
actions_extendedbolus_cancel.setOnClickListener {
extendedBolusCancel?.setOnClickListener {
if (activePlugin.activeTreatments.isInHistoryExtendedBoluslInProgress) {
aapsLogger.debug("USER ENTRY: CANCEL EXTENDED BOLUS")
commandQueue.cancelExtended(object : Callback() {
@ -121,10 +167,10 @@ class ActionsFragment : DaggerFragment() {
})
}
}
actions_settempbasal.setOnClickListener {
setTempBasal?.setOnClickListener {
TempBasalDialog().show(childFragmentManager, "Actions")
}
actions_canceltempbasal.setOnClickListener {
cancelTempBasal?.setOnClickListener {
if (activePlugin.activeTreatments.isTempBasalInProgress) {
aapsLogger.debug("USER ENTRY: CANCEL TEMP BASAL")
commandQueue.cancelTempBasal(true, object : Callback() {
@ -141,32 +187,32 @@ class ActionsFragment : DaggerFragment() {
})
}
}
actions_fill.setOnClickListener {
fill?.setOnClickListener {
activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { FillDialog().show(childFragmentManager, "FillDialog") })
}
}
actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
actions_tddstats.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
actions_bgcheck.setOnClickListener {
historyBrowser?.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) }
tddStats?.setOnClickListener { startActivity(Intent(context, TDDStatsActivity::class.java)) }
view.findViewById<SingleClickButton>(R.id.actions_bgcheck).setOnClickListener {
CareDialog().setOptions(CareDialog.EventType.BGCHECK, R.string.careportal_bgcheck).show(childFragmentManager, "Actions")
}
actions_cgmsensorinsert.setOnClickListener {
view.findViewById<SingleClickButton>(R.id.actions_cgmsensorinsert).setOnClickListener {
CareDialog().setOptions(CareDialog.EventType.SENSOR_INSERT, R.string.careportal_cgmsensorinsert).show(childFragmentManager, "Actions")
}
actions_pumpbatterychange.setOnClickListener {
pumpBatteryChange?.setOnClickListener {
CareDialog().setOptions(CareDialog.EventType.BATTERY_CHANGE, R.string.careportal_pumpbatterychange).show(childFragmentManager, "Actions")
}
actions_note.setOnClickListener {
view.findViewById<SingleClickButton>(R.id.actions_note).setOnClickListener {
CareDialog().setOptions(CareDialog.EventType.NOTE, R.string.careportal_note).show(childFragmentManager, "Actions")
}
actions_exercise.setOnClickListener {
view.findViewById<SingleClickButton>(R.id.actions_exercise).setOnClickListener {
CareDialog().setOptions(CareDialog.EventType.EXERCISE, R.string.careportal_exercise).show(childFragmentManager, "Actions")
}
actions_question.setOnClickListener {
view.findViewById<SingleClickButton>(R.id.actions_question).setOnClickListener {
CareDialog().setOptions(CareDialog.EventType.QUESTION, R.string.careportal_question).show(childFragmentManager, "Actions")
}
actions_announcement.setOnClickListener {
view.findViewById<SingleClickButton>(R.id.actions_announcement).setOnClickListener {
CareDialog().setOptions(CareDialog.EventType.ANNOUNCEMENT, R.string.careportal_announcement).show(childFragmentManager, "Actions")
}
@ -178,28 +224,28 @@ class ActionsFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventInitializationChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventRefreshOverview::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventExtendedBolusChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventTempBasalChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventCustomActionsChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventCareportalEventChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
updateGui()
}
@ -215,58 +261,58 @@ class ActionsFragment : DaggerFragment() {
val profile = profileFunction.getProfile()
val pump = activePlugin.activePump
actions_profileswitch?.visibility = (
profileSwitch?.visibility = (
activePlugin.activeProfileInterface.profile != null &&
pump.pumpDescription.isSetBasalProfileCapable &&
pump.isInitialized &&
!pump.isSuspended).toVisibility()
if (!pump.pumpDescription.isExtendedBolusCapable || !pump.isInitialized || pump.isSuspended || pump.isFakingTempsByExtendedBoluses) {
actions_extendedbolus?.visibility = View.GONE
actions_extendedbolus_cancel?.visibility = View.GONE
extendedBolus?.visibility = View.GONE
extendedBolusCancel?.visibility = View.GONE
} else {
val activeExtendedBolus = activePlugin.activeTreatments.getExtendedBolusFromHistory(System.currentTimeMillis())
if (activeExtendedBolus != null) {
actions_extendedbolus?.visibility = View.GONE
actions_extendedbolus_cancel?.visibility = View.VISIBLE
extendedBolus?.visibility = View.GONE
extendedBolusCancel?.visibility = View.VISIBLE
@Suppress("SetTextI18n")
actions_extendedbolus_cancel?.text = resourceHelper.gs(R.string.cancel) + " " + activeExtendedBolus.toStringMedium()
extendedBolusCancel?.text = resourceHelper.gs(R.string.cancel) + " " + activeExtendedBolus.toStringMedium()
} else {
actions_extendedbolus?.visibility = View.VISIBLE
actions_extendedbolus_cancel?.visibility = View.GONE
extendedBolus?.visibility = View.VISIBLE
extendedBolusCancel?.visibility = View.GONE
}
}
if (!pump.pumpDescription.isTempBasalCapable || !pump.isInitialized || pump.isSuspended) {
actions_settempbasal?.visibility = View.GONE
actions_canceltempbasal?.visibility = View.GONE
setTempBasal?.visibility = View.GONE
cancelTempBasal?.visibility = View.GONE
} else {
val activeTemp = activePlugin.activeTreatments.getTempBasalFromHistory(System.currentTimeMillis())
if (activeTemp != null) {
actions_settempbasal?.visibility = View.GONE
actions_canceltempbasal?.visibility = View.VISIBLE
setTempBasal?.visibility = View.GONE
cancelTempBasal?.visibility = View.VISIBLE
@Suppress("SetTextI18n")
actions_canceltempbasal?.text = resourceHelper.gs(R.string.cancel) + " " + activeTemp.toStringShort()
cancelTempBasal?.text = resourceHelper.gs(R.string.cancel) + " " + activeTemp.toStringShort()
} else {
actions_settempbasal?.visibility = View.VISIBLE
actions_canceltempbasal?.visibility = View.GONE
setTempBasal?.visibility = View.VISIBLE
cancelTempBasal?.visibility = View.GONE
}
}
val activeBgSource = activePlugin.activeBgSource
actions_historybrowser.visibility = (profile != null).toVisibility()
actions_fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized && !pump.isSuspended).toVisibility()
actions_pumpbatterychange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
actions_temptarget?.visibility = (profile != null && config.APS).toVisibility()
actions_tddstats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
historyBrowser?.visibility = (profile != null).toVisibility()
fill?.visibility = (pump.pumpDescription.isRefillingCapable && pump.isInitialized && !pump.isSuspended).toVisibility()
pumpBatteryChange?.visibility = (pump.pumpDescription.isBatteryReplaceable || (pump is OmnipodErosPumpPlugin && pump.isUseRileyLinkBatteryLevel && pump.isBatteryChangeLoggingEnabled)).toVisibility()
tempTarget?.visibility = (profile != null && config.APS).toVisibility()
tddStats?.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
if (!config.NSCLIENT) {
statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, careportal_reservoirlevel, careportal_sensorage, careportal_sensorlevel, careportal_pbage, careportal_batterylevel)
careportal_senslevellabel?.text = if (activeBgSource.sensorBatteryLevel == -1) "" else resourceHelper.gs(R.string.careportal_level_label)
statusLightHandler.updateStatusLights(cannulaAge, insulinAge, reservoirLevel, sensorAge, sensorLevel, pbAge, batteryLevel)
sensorLevelLabel?.text = if (activeBgSource.sensorBatteryLevel == -1) "" else resourceHelper.gs(R.string.careportal_level_label)
} else {
statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, null, careportal_sensorage, null, careportal_pbage, null)
careportal_senslevellabel?.text = ""
careportal_inslevellabel?.text = ""
careportal_pblevellabel?.text = ""
statusLightHandler.updateStatusLights(cannulaAge, insulinAge, null, sensorAge, null, pbAge, null)
sensorLevelLabel?.text = ""
insulinLevelLabel?.text = ""
pbLevelLabel?.text = ""
}
checkPumpCustomActions()
@ -298,7 +344,7 @@ class ActionsFragment : DaggerFragment() {
val top = activity?.let { ContextCompat.getDrawable(it, customAction.iconResourceId) }
btn.setCompoundDrawablesWithIntrinsicBounds(null, top, null, null)
action_buttons_layout?.addView(btn)
buttonsLayout?.addView(btn)
this.pumpCustomActions[resourceHelper.gs(customAction.name)] = customAction
this.pumpCustomButtons.add(btn)
@ -306,7 +352,7 @@ class ActionsFragment : DaggerFragment() {
}
private fun removePumpCustomActions() {
for (customButton in pumpCustomButtons) action_buttons_layout?.removeView(customButton)
for (customButton in pumpCustomButtons) buttonsLayout?.removeView(customButton)
pumpCustomButtons.clear()
}
}

View file

@ -43,6 +43,12 @@ class AutomationEvent(private val injector: HasAndroidInjector) {
fun addAction(action: Action) = actions.add(action)
fun areActionsValid() : Boolean {
var result = true
for (action in actions) result = result && action.isValid()
return result
}
fun toJSON(): String {
val array = JSONArray()
for (a in actions) array.put(a.toJSON())

View file

@ -35,13 +35,14 @@ import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import java.util.*
import javax.inject.Inject
class AutomationFragment : DaggerFragment(), OnStartDragListener {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@ -93,16 +94,16 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
super.onResume()
disposable += rxBus
.toObservable(EventAutomationUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
updateGui()
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAutomationDataChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
eventListAdapter.notifyDataSetChanged()
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
updateGui()
}
@ -162,6 +163,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@SuppressLint("ClickableViewAccessibility")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val event = automationPlugin.at(position)
holder.binding.rootLayout.setBackgroundColor(resourceHelper.gc(if (event.areActionsValid()) R.color.ribbonDefault else R.color.errorAlertBackground))
holder.binding.eventTitle.text = event.title
holder.binding.enabled.isChecked = event.isEnabled
holder.binding.enabled.isEnabled = !event.readOnly

View file

@ -32,9 +32,9 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@ -54,6 +54,7 @@ class AutomationPlugin @Inject constructor(
private val rxBus: RxBusWrapper,
private val constraintChecker: ConstraintChecker,
aapsLogger: AAPSLogger,
private val aapsSchedulers: AapsSchedulers,
private val config: Config,
private val locationServiceHelper: LocationServiceHelper,
private val dateUtil: DateUtil
@ -103,7 +104,7 @@ class AutomationPlugin @Inject constructor(
disposable += rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ e ->
if (e.isChanged(resourceHelper, R.string.key_location)) {
locationServiceHelper.stopService(context)
@ -112,11 +113,11 @@ class AutomationPlugin @Inject constructor(
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAutomationDataChanged::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ storeToSP() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventLocationChange::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ e ->
e?.let {
aapsLogger.debug(LTag.AUTOMATION, "Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider")
@ -125,19 +126,19 @@ class AutomationPlugin @Inject constructor(
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventChargingState::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ processActions() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNetworkChange::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ processActions() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ processActions() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventBTChange::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({
aapsLogger.debug(LTag.AUTOMATION, "Grabbed new BT event: $it")
btConnects.add(it)
@ -200,30 +201,36 @@ class AutomationPlugin @Inject constructor(
}
aapsLogger.debug(LTag.AUTOMATION, "processActions")
val iterator : MutableIterator<AutomationEvent> = automationEvents.iterator()
val iterator: MutableIterator<AutomationEvent> = automationEvents.iterator()
while (iterator.hasNext()) {
val event = iterator.next()
if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) {
if (event.systemAction || userEventsEnabled) {
val actions = event.actions
for (action in actions) {
action.doAction(object : Callback() {
override fun run() {
val sb = StringBuilder()
sb.append(dateUtil.timeString(DateUtil.now()))
sb.append(" ")
sb.append(if (result.success) "" else "")
sb.append(" <b>")
sb.append(event.title)
sb.append(":</b> ")
sb.append(action.shortDescription())
sb.append(": ")
sb.append(result.comment)
executionLog.add(sb.toString())
aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb")
rxBus.send(EventAutomationUpdateGui())
}
})
if (action.isValid())
action.doAction(object : Callback() {
override fun run() {
val sb = StringBuilder()
sb.append(dateUtil.timeString(DateUtil.now()))
sb.append(" ")
sb.append(if (result.success) "" else "")
sb.append(" <b>")
sb.append(event.title)
sb.append(":</b> ")
sb.append(action.shortDescription())
sb.append(": ")
sb.append(result.comment)
executionLog.add(sb.toString())
aapsLogger.debug(LTag.AUTOMATION, "Executed: $sb")
rxBus.send(EventAutomationUpdateGui())
}
})
else {
executionLog.add("Invalid action: ${action.shortDescription()}")
aapsLogger.debug(LTag.AUTOMATION, "Invalid action: ${action.shortDescription()}")
rxBus.send(EventAutomationUpdateGui())
}
}
SystemClock.sleep(1100)
event.lastRun = DateUtil.now()

View file

@ -12,6 +12,7 @@ import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor
abstract class Action(val injector: HasAndroidInjector) {
@Inject lateinit var aapsLogger: AAPSLogger
var precondition: Trigger? = null
@ -19,6 +20,7 @@ abstract class Action(val injector: HasAndroidInjector) {
abstract fun friendlyName(): Int
abstract fun shortDescription(): String
abstract fun doAction(callback: Callback)
abstract fun isValid(): Boolean
@DrawableRes abstract fun icon(): Int
init {

View file

@ -40,6 +40,8 @@ class ActionAlarm(injector: HasAndroidInjector) : Action(injector) {
override fun shortDescription(): String = resourceHelper.gs(R.string.alarm_message, text.value)
@DrawableRes override fun icon(): Int = R.drawable.ic_access_alarm_24dp
override fun isValid(): Boolean = text.value.isNotEmpty()
override fun doAction(callback: Callback) {
val i = Intent(context, ErrorHelperActivity::class.java)
i.putExtra("soundid", R.raw.modern_alarm)

View file

@ -18,6 +18,8 @@ class ActionDummy(injector: HasAndroidInjector) : Action(injector) {
throw NotImplementedError("An operation is not implemented")
}
override fun isValid(): Boolean = false
override fun icon(): Int {
throw NotImplementedError("An operation is not implemented")
}

View file

@ -39,4 +39,6 @@ class ActionLoopDisable(injector: HasAndroidInjector) : Action(injector) {
callback.result(PumpEnactResult(injector).success(true).comment(R.string.alreadydisabled)).run()
}
}
override fun isValid(): Boolean = true
}

View file

@ -14,6 +14,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
class ActionLoopEnable(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@ -34,4 +35,5 @@ class ActionLoopEnable(injector: HasAndroidInjector) : Action(injector) {
}
}
override fun isValid(): Boolean = true
}

View file

@ -33,4 +33,6 @@ class ActionLoopResume(injector: HasAndroidInjector) : Action(injector) {
callback.result(PumpEnactResult(injector).success(true).comment(R.string.notsuspended))?.run()
}
}
override fun isValid(): Boolean = true
}

View file

@ -22,7 +22,7 @@ class ActionLoopSuspend(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var loopPlugin: LoopPlugin
@Inject lateinit var rxBus: RxBusWrapper
var minutes = InputDuration(injector, 0, InputDuration.TimeUnit.MINUTES)
var minutes = InputDuration(injector, 30, InputDuration.TimeUnit.MINUTES)
override fun friendlyName(): Int = R.string.suspendloop
override fun shortDescription(): String = resourceHelper.gs(R.string.suspendloopforXmin, minutes.getMinutes())
@ -59,4 +59,6 @@ class ActionLoopSuspend(injector: HasAndroidInjector) : Action(injector) {
.add(LabelWithElement(injector, resourceHelper.gs(R.string.careportal_newnstreatment_duration_min_label), "", minutes))
.build(root)
}
override fun isValid(): Boolean = minutes.value > 5
}

View file

@ -59,4 +59,6 @@ class ActionNotification(injector: HasAndroidInjector) : Action(injector) {
.add(LabelWithElement(injector, resourceHelper.gs(R.string.message_short), "", text))
.build(root)
}
override fun isValid(): Boolean = text.value.isNotEmpty()
}

View file

@ -78,4 +78,6 @@ class ActionProfileSwitch(injector: HasAndroidInjector) : Action(injector) {
inputProfileName.value = JsonHelper.safeGetString(o, "profileToSwitchTo", "")
return this
}
override fun isValid(): Boolean = activePlugin.activeProfileInterface.profile?.getSpecificProfile(inputProfileName.value) != null
}

View file

@ -23,7 +23,7 @@ class ActionProfileSwitchPercent(injector: HasAndroidInjector) : Action(injector
@Inject lateinit var activePlugin: ActivePluginProvider
var pct = InputPercent(injector)
var duration = InputDuration(injector, 0, InputDuration.TimeUnit.MINUTES)
var duration = InputDuration(injector, 30, InputDuration.TimeUnit.MINUTES)
override fun friendlyName(): Int = R.string.profilepercentage
override fun shortDescription(): String =
@ -66,4 +66,9 @@ class ActionProfileSwitchPercent(injector: HasAndroidInjector) : Action(injector
duration.value = JsonHelper.safeGetInt(o, "durationInMinutes")
return this
}
override fun isValid(): Boolean =
pct.value >= InputPercent.MIN &&
pct.value <= InputPercent.MAX &&
duration.value > 0
}

View file

@ -15,6 +15,7 @@ import org.json.JSONObject
import javax.inject.Inject
class ActionSendSMS(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@ -29,6 +30,8 @@ class ActionSendSMS(injector: HasAndroidInjector) : Action(injector) {
callback.result(PumpEnactResult(injector).success(result).comment(if (result) R.string.ok else R.string.error))?.run()
}
override fun isValid(): Boolean = text.value.isNotEmpty()
override fun toJSON(): String {
val data = JSONObject().put("text", text.value)
return JSONObject()

View file

@ -25,11 +25,12 @@ import org.json.JSONObject
import javax.inject.Inject
class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activePlugin: ActivePluginProvider
var value = InputTempTarget(injector)
var duration = InputDuration(injector, 0, InputDuration.TimeUnit.MINUTES)
var duration = InputDuration(injector, 30, InputDuration.TimeUnit.MINUTES)
init {
precondition = TriggerTempTarget(injector, ComparatorExists.Compare.NOT_EXISTS)
@ -83,4 +84,15 @@ class ActionStartTempTarget(injector: HasAndroidInjector) : Action(injector) {
.source(Source.USER)
.low(Profile.toMgdl(value.value, value.units))
.high(Profile.toMgdl(value.value, value.units))
override fun isValid(): Boolean =
if (value.units == Constants.MMOL) { // mmol
value.value >= Constants.MIN_TT_MMOL &&
value.value <= Constants.MAX_TT_MMOL &&
duration.value > 0
} else { // mg/dL
value.value >= Constants.MIN_TT_MGDL &&
value.value <= Constants.MAX_TT_MGDL &&
duration.value > 0
}
}

View file

@ -12,6 +12,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
class ActionStopTempTarget(injector: HasAndroidInjector) : Action(injector) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var activePlugin: ActivePluginProvider
@ -29,4 +30,6 @@ class ActionStopTempTarget(injector: HasAndroidInjector) : Action(injector) {
activePlugin.activeTreatments.addToHistoryTempTarget(tempTarget)
callback.result(PumpEnactResult(injector).success(true).comment(R.string.ok))?.run()
}
override fun isValid(): Boolean = true
}

View file

@ -9,7 +9,7 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.MainApp
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.AutomationDialogEventBinding
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
@ -27,14 +27,15 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.toVisibility
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject
class EditEventDialog : DialogFragmentWithDate() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp: MainApp
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var automationPlugin: AutomationPlugin
@ -52,11 +53,11 @@ class EditEventDialog : DialogFragmentWithDate() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
event = AutomationEvent(mainApp)
event = AutomationEvent(injector)
// load data from bundle
(savedInstanceState ?: arguments)?.let { bundle ->
position = bundle.getInt("position", -1)
bundle.getString("event")?.let { event = AutomationEvent(mainApp).fromJSON(it) }
bundle.getString("event")?.let { event = AutomationEvent(injector).fromJSON(it) }
}
onCreateViewGeneral()
@ -94,28 +95,28 @@ class EditEventDialog : DialogFragmentWithDate() {
disposable += rxBus
.toObservable(EventAutomationUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
actionListAdapter?.notifyDataSetChanged()
showPreconditions()
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAutomationAddAction::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
event.addAction(it.action)
actionListAdapter?.notifyDataSetChanged()
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAutomationUpdateTrigger::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
event.trigger = it.trigger
binding.triggerDescription.text = event.trigger.friendlyDescription()
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAutomationUpdateAction::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
event.actions[it.position] = it.action
actionListAdapter?.notifyDataSetChanged()

View file

@ -4,7 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import info.nightscout.androidaps.MainApp
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.databinding.AutomationDialogEditTriggerBinding
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -17,15 +17,16 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerCon
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import org.json.JSONObject
import javax.inject.Inject
class EditTriggerDialog : DialogFragmentWithDate() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp: MainApp
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var fabricPrivacy: FabricPrivacy
private var disposable: CompositeDisposable = CompositeDisposable()
@ -42,7 +43,7 @@ class EditTriggerDialog : DialogFragmentWithDate() {
savedInstanceState: Bundle?): View {
// load data from bundle
(savedInstanceState ?: arguments)?.let { bundle ->
bundle.getString("trigger")?.let { triggers = TriggerDummy(mainApp).instantiate(JSONObject(it)) }
bundle.getString("trigger")?.let { triggers = TriggerDummy(injector).instantiate(JSONObject(it)) }
}
onCreateViewGeneral()
@ -55,28 +56,28 @@ class EditTriggerDialog : DialogFragmentWithDate() {
disposable += rxBus
.toObservable(EventTriggerChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
binding.layoutTrigger.removeAllViews()
triggers?.generateDialog(binding.layoutTrigger)
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventTriggerRemove::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
findParent(triggers, it.trigger)?.list?.remove(it.trigger)
binding.layoutTrigger.removeAllViews()
triggers?.generateDialog(binding.layoutTrigger)
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventTriggerClone::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
findParent(triggers, it.trigger)?.list?.add(it.trigger.duplicate())
binding.layoutTrigger.removeAllViews()
triggers?.generateDialog(binding.layoutTrigger)
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
// display root trigger
triggers?.generateDialog(binding.layoutTrigger)

View file

@ -24,12 +24,11 @@ class InputDuration(injector: HasAndroidInjector) : Element(injector) {
val numberPicker : NumberPicker
if (unit == TimeUnit.MINUTES) {
numberPicker = MinutesNumberPicker(root.context, null)
numberPicker.setParams(0.0, 0.0, 24 * 60.0, 10.0, DecimalFormat("0"), false, root.findViewById(R.id.ok))
numberPicker.setParams(value.toDouble(), 5.0, 24 * 60.0, 10.0, DecimalFormat("0"), false, root.findViewById(R.id.ok))
} else {
numberPicker = NumberPicker(root.context, null)
numberPicker.setParams(0.0, 0.0, 24.0, 1.0, DecimalFormat("0"), false, root.findViewById(R.id.ok))
numberPicker.setParams(value.toDouble(), 1.0, 24.0, 1.0, DecimalFormat("0"), false, root.findViewById(R.id.ok))
}
numberPicker.value = value.toDouble()
numberPicker.setOnValueChangedListener { value: Double -> this.value = value.toInt() }
root.addView(numberPicker)
}

View file

@ -16,7 +16,7 @@ import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import org.json.JSONObject
class TriggerBolusAgo(injector: HasAndroidInjector) : Trigger(injector) {
var minutesAgo: InputDuration = InputDuration(injector, 0, InputDuration.TimeUnit.MINUTES)
var minutesAgo: InputDuration = InputDuration(injector, 30, InputDuration.TimeUnit.MINUTES)
var comparator: Comparator = Comparator(injector)
private constructor(injector: HasAndroidInjector, triggerBolusAgo: TriggerBolusAgo) : this(injector) {

View file

@ -8,7 +8,6 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.events.Event
import info.nightscout.androidaps.events.EventExtendedBolusChange
import info.nightscout.androidaps.events.EventNewBasalProfile
@ -30,8 +29,8 @@ import info.nightscout.androidaps.services.Intents
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
import javax.inject.Singleton
@ -40,6 +39,7 @@ class DataBroadcastPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
private val aapsSchedulers: AapsSchedulers,
private val context: Context,
private val fabricPrivacy: FabricPrivacy,
private val rxBus: RxBusWrapper,
@ -67,32 +67,32 @@ class DataBroadcastPlugin @Inject constructor(
super.onStart()
disposable.add(rxBus
.toObservable(EventOpenAPSUpdateGui::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendData(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendData(it) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventExtendedBolusChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendData(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendData(it) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTempBasalChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendData(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendData(it) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTreatmentChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendData(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendData(it) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventNewBasalProfile::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendData(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendData(it) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendData(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendData(it) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventOverviewBolusProgress::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendData(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendData(it) }, fabricPrivacy::logException))
}
override fun onStop() {
@ -122,13 +122,13 @@ class DataBroadcastPlugin @Inject constructor(
}
private fun bgStatus(bundle: Bundle) {
val lastBG: BgReading = iobCobCalculatorPlugin.lastBg() ?: return
val lastBG = iobCobCalculatorPlugin.lastBg() ?: return
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData ?: return
bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl
bundle.putLong("glucoseTimeStamp", lastBG.date) // timestamp
bundle.putLong("glucoseTimeStamp", lastBG.timestamp) // timestamp
bundle.putString("units", profileFunction.getUnits()) // units used in AAPS "mg/dl" or "mmol"
bundle.putString("slopeArrow", lastBG.directionToSymbol(databaseHelper)) // direction arrow as string
bundle.putString("slopeArrow", lastBG.trendArrow.text) // direction arrow as string
bundle.putDouble("deltaMgdl", glucoseStatus.delta) // bg delta in mgdl
bundle.putDouble("avgDeltaMgdl", glucoseStatus.avgdelta) // average bg delta
bundle.putDouble("high", defaultValueHelper.determineHighLine()) // predefined top value of in range (green area)

View file

@ -24,7 +24,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.showConfirmation
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import java.util.*
import javax.inject.Inject
@ -32,6 +32,7 @@ import kotlin.collections.ArrayList
class FoodFragment : DaggerFragment() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@ -106,8 +107,8 @@ class FoodFragment : DaggerFragment() {
super.onResume()
disposable.add(rxBus
.toObservable(EventFoodDatabaseChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
)
updateGui()
}

View file

@ -36,8 +36,8 @@ import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
/**
* Created by mike on 24.09.2017.
@ -47,6 +47,7 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
@Inject AAPSLogger aapsLogger;
@Inject RxBusWrapper rxBus;
@Inject FabricPrivacy fabricPrivacy;
@Inject AapsSchedulers aapsSchedulers;
private final CompositeDisposable disposable = new CompositeDisposable();
@ -59,7 +60,7 @@ public class FoodService extends OrmLiteBaseService<DatabaseHelper> {
dbInitialize();
disposable.add(rxBus
.toObservable(EventNsFood.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
int mode = event.getMode();
JSONArray array = event.getFoods();

View file

@ -8,23 +8,36 @@ import android.view.ViewGroup
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.databinding.MaintenanceFragmentBinding
import info.nightscout.androidaps.events.EventNewBG
import info.nightscout.androidaps.interfaces.ImportExportPrefsInterface
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.Completable.fromAction
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.subscribeBy
import javax.inject.Inject
class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var maintenancePlugin: MaintenancePlugin
@Inject lateinit var mainApp: MainApp
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var foodPlugin: FoodPlugin
@Inject lateinit var importExportPrefs: ImportExportPrefsInterface
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var repository: AppRepository
private val compositeDisposable = CompositeDisposable()
private var _binding: MaintenanceFragmentBinding? = null
@ -40,25 +53,42 @@ class MaintenanceFragment : DaggerFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.logSend.setOnClickListener { maintenancePlugin.sendLogs() }
binding.logDelete.setOnClickListener { maintenancePlugin.deleteLogs() }
binding.logDelete.setOnClickListener {
aapsLogger.debug("USER ENTRY: DELETE LOGS")
maintenancePlugin.deleteLogs()
}
binding.navResetdb.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.maintenance), resourceHelper.gs(R.string.reset_db_confirm), Runnable {
MainApp.getDbHelper().resetDatabases()
// should be handled by Plugin-Interface and
// additional service interface and plugin registry
foodPlugin.service?.resetFood()
treatmentsPlugin.service.resetTreatments()
aapsLogger.debug("USER ENTRY: RESET DATABASES")
compositeDisposable.add(
fromAction {
MainApp.getDbHelper().resetDatabases()
// should be handled by Plugin-Interface and
// additional service interface and plugin registry
foodPlugin.service?.resetFood()
treatmentsPlugin.service.resetTreatments()
repository.clearDatabases()
}
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
.subscribeBy(
onError = { aapsLogger.error("Error clearing databases", it) },
onComplete = { rxBus.send(EventNewBG(null)) }
)
)
})
}
}
binding.navExport.setOnClickListener {
aapsLogger.debug("USER ENTRY: EXPORT SETTINGS")
// start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.exportSharedPreferences(this)
}
}
binding.navImport.setOnClickListener {
aapsLogger.debug("USER ENTRY: IMPORT SETTINGS")
// start activity for checking permissions...
importExportPrefs.verifyStoragePermissions(this) {
importExportPrefs.importSharedPreferences(this)
@ -70,6 +100,7 @@ class MaintenanceFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
compositeDisposable.clear()
_binding = null
}
}

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.general.nsclient;
import android.graphics.Paint;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.View;
@ -25,8 +24,8 @@ import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.HtmlHelper;
import info.nightscout.androidaps.utils.alertDialogs.OKDialog;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
public class NSClientFragment extends DaggerFragment implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
@ -36,6 +35,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
@Inject RxBusWrapper rxBus;
@Inject UploadQueue uploadQueue;
@Inject FabricPrivacy fabricPrivacy;
@Inject AapsSchedulers aapsSchedulers;
private final CompositeDisposable disposable = new CompositeDisposable();
@ -93,7 +93,7 @@ public class NSClientFragment extends DaggerFragment implements View.OnClickList
super.onResume();
disposable.add(rxBus
.toObservable(EventNSClientUpdateGUI.class)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.getMain())
.subscribe(event -> updateGui(), fabricPrivacy::logException)
);
updateGui();

View file

@ -4,6 +4,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@ -13,6 +14,9 @@ import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreference;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
@ -23,11 +27,15 @@ import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.CareportalEvent;
import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventChargingState;
import info.nightscout.androidaps.events.EventNetworkChange;
import info.nightscout.androidaps.events.EventNsTreatment;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
@ -36,19 +44,24 @@ import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.general.nsclient.data.AlarmAck;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSMbg;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientNewLog;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientResend;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientStatus;
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI;
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.services.Intents;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.HtmlHelper;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.ToastUtils;
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
@Singleton
public class NSClientPlugin extends PluginBase {
@ -58,10 +71,13 @@ public class NSClientPlugin extends PluginBase {
private final RxBusWrapper rxBus;
private final ResourceHelper resourceHelper;
private final Context context;
private final AapsSchedulers aapsSchedulers;
private final FabricPrivacy fabricPrivacy;
private final SP sp;
private final Config config;
private final BuildHelper buildHelper;
private final ActivePluginProvider activePlugin;
private final NSUpload nsUpload;
public Handler handler;
@ -81,6 +97,7 @@ public class NSClientPlugin extends PluginBase {
public NSClientPlugin(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
AapsSchedulers aapsSchedulers,
RxBusWrapper rxBus,
ResourceHelper resourceHelper,
Context context,
@ -88,7 +105,9 @@ public class NSClientPlugin extends PluginBase {
SP sp,
NsClientReceiverDelegate nsClientReceiverDelegate,
Config config,
BuildHelper buildHelper
BuildHelper buildHelper,
ActivePluginProvider activePlugin,
NSUpload nsUpload
) {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
@ -102,6 +121,7 @@ public class NSClientPlugin extends PluginBase {
);
this.aapsLogger = aapsLogger;
this.aapsSchedulers = aapsSchedulers;
this.rxBus = rxBus;
this.resourceHelper = resourceHelper;
this.context = context;
@ -110,6 +130,8 @@ public class NSClientPlugin extends PluginBase {
this.nsClientReceiverDelegate = nsClientReceiverDelegate;
this.config = config;
this.buildHelper = buildHelper;
this.activePlugin = activePlugin;
this.nsUpload = nsUpload;
if (config.getNSCLIENT()) {
getPluginDescription().alwaysEnabled(true).visibleByDefault(true);
@ -139,7 +161,7 @@ public class NSClientPlugin extends PluginBase {
nsClientReceiverDelegate.grabReceiversState();
disposable.add(rxBus
.toObservable(EventNSClientStatus.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
status = event.getStatus(resourceHelper);
rxBus.send(new EventNSClientUpdateGUI());
@ -147,17 +169,17 @@ public class NSClientPlugin extends PluginBase {
);
disposable.add(rxBus
.toObservable(EventNetworkChange.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventPreferenceChange.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventAppExit.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
if (nsClientService != null) {
context.unbindService(mConnection);
@ -166,7 +188,7 @@ public class NSClientPlugin extends PluginBase {
);
disposable.add(rxBus
.toObservable(EventNSClientNewLog.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
addToLog(event);
aapsLogger.debug(LTag.NSCLIENT, event.getAction() + " " + event.getLogText());
@ -174,12 +196,12 @@ public class NSClientPlugin extends PluginBase {
);
disposable.add(rxBus
.toObservable(EventChargingState.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> nsClientReceiverDelegate.onStatusEvent(event), fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(EventNSClientResend.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> resend(event.getReason()), fabricPrivacy::logException)
);
}
@ -310,4 +332,143 @@ public class NSClientPlugin extends PluginBase {
nsClientService.sendAlarmAck(ack);
}
// Parsing input data
public void handleNewDataFromNSClient(String action, Bundle bundle) {
boolean acceptNSData = !sp.getBoolean(R.string.key_ns_upload_only, true) && buildHelper.isEngineeringMode() || config.getNSCLIENT();
if (!acceptNSData) return;
aapsLogger.debug(LTag.DATASERVICE, "Got intent: " + action);
if (action.equals(Intents.ACTION_NEW_TREATMENT) || action.equals(Intents.ACTION_CHANGED_TREATMENT)) {
try {
if (bundle.containsKey("treatment")) {
JSONObject json = new JSONObject(bundle.getString("treatment"));
handleTreatmentFromNS(json, action);
}
if (bundle.containsKey("treatments")) {
String trstring = bundle.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
handleTreatmentFromNS(json, action);
}
}
} catch (JSONException e) {
aapsLogger.error(LTag.DATASERVICE, "Unhandled exception", e);
}
}
if (action.equals(Intents.ACTION_REMOVED_TREATMENT)) {
try {
if (bundle.containsKey("treatment")) {
String trstring = bundle.getString("treatment");
JSONObject json = new JSONObject(trstring);
handleRemovedTreatmentFromNS(json);
}
if (bundle.containsKey("treatments")) {
String trstring = bundle.getString("treatments");
JSONArray jsonArray = new JSONArray(trstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
handleRemovedTreatmentFromNS(json);
}
}
} catch (JSONException e) {
aapsLogger.error(LTag.DATASERVICE, "Unhandled exception", e);
}
}
if (action.equals(Intents.ACTION_NEW_MBG)) {
try {
if (bundle.containsKey("mbg")) {
String mbgstring = bundle.getString("mbg");
JSONObject mbgJson = new JSONObject(mbgstring);
storeMbg(mbgJson);
}
if (bundle.containsKey("mbgs")) {
String sgvstring = bundle.getString("mbgs");
JSONArray jsonArray = new JSONArray(sgvstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject mbgJson = jsonArray.getJSONObject(i);
storeMbg(mbgJson);
}
}
} catch (Exception e) {
aapsLogger.error(LTag.DATASERVICE, "Unhandled exception", e);
}
}
}
private void handleRemovedTreatmentFromNS(JSONObject json) {
// new DB model
EventNsTreatment evtTreatment = new EventNsTreatment(EventNsTreatment.Companion.getREMOVE(), json);
rxBus.send(evtTreatment);
// old DB model
String _id = JsonHelper.safeGetString(json, "_id");
MainApp.getDbHelper().deleteTempTargetById(_id);
MainApp.getDbHelper().deleteTempBasalById(_id);
MainApp.getDbHelper().deleteExtendedBolusById(_id);
MainApp.getDbHelper().deleteCareportalEventById(_id);
MainApp.getDbHelper().deleteProfileSwitchById(_id);
}
private void handleTreatmentFromNS(JSONObject json, String action) {
// new DB model
int mode = Intents.ACTION_NEW_TREATMENT.equals(action) ? EventNsTreatment.Companion.getADD() : EventNsTreatment.Companion.getUPDATE();
double insulin = JsonHelper.safeGetDouble(json, "insulin");
double carbs = JsonHelper.safeGetDouble(json, "carbs");
String eventType = JsonHelper.safeGetString(json, "eventType");
if (eventType == null) {
aapsLogger.debug(LTag.DATASERVICE, "Wrong treatment. Ignoring : " + json.toString());
return;
}
if (insulin > 0 || carbs > 0) {
EventNsTreatment evtTreatment = new EventNsTreatment(mode, json);
rxBus.send(evtTreatment);
} else if (eventType.equals(CareportalEvent.TEMPORARYTARGET)) {
MainApp.getDbHelper().createTemptargetFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.TEMPBASAL)) {
MainApp.getDbHelper().createTempBasalFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.COMBOBOLUS)) {
MainApp.getDbHelper().createExtendedBolusFromJsonIfNotExists(json);
} else if (eventType.equals(CareportalEvent.PROFILESWITCH)) {
MainApp.getDbHelper().createProfileSwitchFromJsonIfNotExists(activePlugin, nsUpload, json);
} else if (eventType.equals(CareportalEvent.SITECHANGE) ||
eventType.equals(CareportalEvent.INSULINCHANGE) ||
eventType.equals(CareportalEvent.SENSORCHANGE) ||
eventType.equals(CareportalEvent.BGCHECK) ||
eventType.equals(CareportalEvent.NOTE) ||
eventType.equals(CareportalEvent.NONE) ||
eventType.equals(CareportalEvent.ANNOUNCEMENT) ||
eventType.equals(CareportalEvent.QUESTION) ||
eventType.equals(CareportalEvent.EXERCISE) ||
eventType.equals(CareportalEvent.OPENAPSOFFLINE) ||
eventType.equals(CareportalEvent.PUMPBATTERYCHANGE)) {
MainApp.getDbHelper().createCareportalEventFromJsonIfNotExists(json);
}
if (eventType.equals(CareportalEvent.ANNOUNCEMENT)) {
long date = JsonHelper.safeGetLong(json, "mills");
long now = System.currentTimeMillis();
String enteredBy = JsonHelper.safeGetString(json, "enteredBy", "");
String notes = JsonHelper.safeGetString(json, "notes", "");
if (date > now - 15 * 60 * 1000L && !notes.isEmpty()
&& !enteredBy.equals(sp.getString("careportal_enteredby", "AndroidAPS"))) {
boolean defaultVal = config.getNSCLIENT();
if (sp.getBoolean(R.string.key_ns_announcements, defaultVal)) {
Notification announcement = new Notification(Notification.NSANNOUNCEMENT, notes, Notification.ANNOUNCEMENT, 60);
rxBus.send(new EventNewNotification(announcement));
}
}
}
}
private void storeMbg(JSONObject mbgJson) {
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
MainApp.getDbHelper().createOrUpdate(careportalEvent);
aapsLogger.debug(LTag.DATASERVICE, "Adding/Updating new MBG: " + careportalEvent.toString());
}
}

View file

@ -0,0 +1,41 @@
package info.nightscout.androidaps.plugins.general.nsclient;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import org.jetbrains.annotations.NotNull;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.receivers.BundleStore;
import info.nightscout.androidaps.receivers.DataReceiver;
// cannot be inner class because of needed injection
public class NSClientWorker extends Worker {
public NSClientWorker(
@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
((HasAndroidInjector) context.getApplicationContext()).androidInjector().inject(this);
}
@Inject NSClientPlugin nsClientPlugin;
@Inject BundleStore bundleStore;
@NotNull
@Override
public Result doWork() {
Bundle bundle = bundleStore.pickup(getInputData().getLong(DataReceiver.STORE_KEY, -1));
if (bundle == null) return Result.failure();
String action = getInputData().getString(DataReceiver.ACTION_KEY);
nsClientPlugin.handleNewDataFromNSClient(action, bundle);
return Result.success();
}
}

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.plugins.general.nsclient.data;
import android.text.Html;
import android.text.Spanned;
import org.json.JSONArray;
@ -15,7 +14,6 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.ConfigInterface;
import info.nightscout.androidaps.logging.AAPSLogger;
@ -475,8 +473,8 @@ public class NSDeviceStatus {
public static APSResult getAPSResult(HasAndroidInjector injector) {
APSResult result = new APSResult(injector);
result.json = deviceStatusOpenAPSData.suggested;
result.date = deviceStatusOpenAPSData.clockSuggested;
result.setJson(deviceStatusOpenAPSData.suggested);
result.setDate(deviceStatusOpenAPSData.clockSuggested);
return result;
}

View file

@ -68,9 +68,9 @@ import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
@ -78,6 +78,7 @@ import io.socket.emitter.Emitter;
public class NSClientService extends DaggerService {
@Inject HasAndroidInjector injector;
@Inject AAPSLogger aapsLogger;
@Inject AapsSchedulers aapsSchedulers;
@Inject NSSettingsStatus nsSettingsStatus;
@Inject NSDeviceStatus nsDeviceStatus;
@Inject DatabaseHelperInterface databaseHelper;
@ -147,7 +148,7 @@ public class NSClientService extends DaggerService {
disposable.add(rxBus
.toObservable(EventConfigBuilderChange.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
if (nsEnabled != nsClientPlugin.isEnabled(PluginType.GENERAL)) {
latestDateInReceivedData = 0;
@ -158,7 +159,7 @@ public class NSClientService extends DaggerService {
);
disposable.add(rxBus
.toObservable(EventPreferenceChange.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
if (event.isChanged(resourceHelper, R.string.key_nsclientinternal_url) ||
event.isChanged(resourceHelper, R.string.key_nsclientinternal_api_secret) ||
@ -172,7 +173,7 @@ public class NSClientService extends DaggerService {
);
disposable.add(rxBus
.toObservable(EventAppExit.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
aapsLogger.debug(LTag.NSCLIENT, "EventAppExit received");
destroy();
@ -181,7 +182,7 @@ public class NSClientService extends DaggerService {
);
disposable.add(rxBus
.toObservable(EventNSClientRestart.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
latestDateInReceivedData = 0;
restart();
@ -189,17 +190,17 @@ public class NSClientService extends DaggerService {
);
disposable.add(rxBus
.toObservable(NSAuthAck.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(this::processAuthAck, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(NSUpdateAck.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(this::processUpdateAck, fabricPrivacy::logException)
);
disposable.add(rxBus
.toObservable(NSAddAck.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(this::processAddAck, fabricPrivacy::logException)
);
}

View file

@ -18,11 +18,10 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.BackpressureStrategy
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@ -37,25 +36,23 @@ class OpenHumansFragment : DaggerFragment() {
private var queueSizeValue = 0L
private val compositeDisposable = CompositeDisposable()
@Inject
lateinit var rxBus: RxBusWrapper
@Inject
lateinit var openHumansUploader: OpenHumansUploader
@Inject
lateinit var resourceHelper: ResourceHelper
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var openHumansUploader: OpenHumansUploader
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var aapsSchedulers: AapsSchedulers
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
compositeDisposable += Single.fromCallable { MainApp.getDbHelper().ohQueueSize }
.subscribeOn(Schedulers.io())
.repeatWhen { rxBus.toObservable(UpdateViewEvent::class.java)
.cast(Any::class.java)
.mergeWith(rxBus.toObservable(UpdateQueueEvent::class.java)
.throttleLatest(5, TimeUnit.SECONDS))
.toFlowable(BackpressureStrategy.LATEST) }
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(aapsSchedulers.io)
.repeatWhen {
rxBus.toObservable(UpdateViewEvent::class.java)
.cast(Any::class.java)
.mergeWith(rxBus.toObservable(UpdateQueueEvent::class.java)
.throttleLatest(5, TimeUnit.SECONDS))
.toFlowable(BackpressureStrategy.LATEST)
}
.observeOn(aapsSchedulers.main)
.subscribe({
queueSizeValue = it
updateGUI()

View file

@ -14,8 +14,8 @@ import androidx.fragment.app.FragmentActivity
import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
@ -45,8 +45,8 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
class ExchangeAuthTokenDialog : DaggerDialogFragment() {
@Inject
lateinit var openHumansUploader: OpenHumansUploader
@Inject lateinit var openHumansUploader: OpenHumansUploader
@Inject lateinit var aapsSchedulers: AapsSchedulers
private var disposable: Disposable? = null
@ -63,7 +63,7 @@ class OpenHumansLoginActivity : NoSplashAppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
disposable = openHumansUploader.login(arguments?.getString("authToken")!!).subscribeOn(Schedulers.io()).subscribe({
disposable = openHumansUploader.login(arguments?.getString("authToken")!!).subscribeOn(aapsSchedulers.io).subscribe({
dismiss()
SetupDoneDialog().show(parentFragmentManager, "SetupDoneDialog")
}, {

View file

@ -16,6 +16,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.db.*
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.PluginBase
@ -27,13 +29,13 @@ import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.Completable
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
@ -52,10 +54,12 @@ class OpenHumansUploader @Inject constructor(
injector: HasAndroidInjector,
resourceHelper: ResourceHelper,
aapsLogger: AAPSLogger,
val sp: SP,
val rxBus: RxBusWrapper,
val context: Context,
val treatmentsPlugin: TreatmentsPlugin
private val aapsSchedulers: AapsSchedulers,
private val sp: SP,
private val rxBus: RxBusWrapper,
private val context: Context,
private val treatmentsPlugin: TreatmentsPlugin,
val repository: AppRepository
) : PluginBase(
PluginDescription()
.mainType(PluginType.GENERAL)
@ -85,6 +89,7 @@ class OpenHumansUploader @Inject constructor(
}
private val openHumansAPI = OpenHumansAPI(OPEN_HUMANS_URL, CLIENT_ID, CLIENT_SECRET, REDIRECT_URL)
@Suppress("PrivatePropertyName")
private val FILE_NAME_DATE_FORMAT = SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.US).apply { timeZone = TimeZone.getTimeZone("UTC") }
@ -159,15 +164,15 @@ class OpenHumansUploader @Inject constructor(
super.onStop()
}
fun enqueueBGReading(bgReading: BgReading?) = bgReading?.let {
fun enqueueBGReading(glucoseValue: GlucoseValue?) = glucoseValue?.let {
insertQueueItem("BgReadings") {
put("date", bgReading.date)
put("isValid", bgReading.isValid)
put("value", bgReading.value)
put("direction", bgReading.direction)
put("raw", bgReading.raw)
put("source", bgReading.source)
put("nsId", bgReading._id)
put("date", glucoseValue.timestamp)
put("isValid", glucoseValue.isValid)
put("value", glucoseValue.value)
put("direction", glucoseValue.trendArrow)
put("raw", glucoseValue.raw)
put("source", glucoseValue.sourceSensor)
put("nsId", glucoseValue.interfaceIDs.nightscoutId)
}
}
@ -361,7 +366,7 @@ class OpenHumansUploader @Inject constructor(
.flatMapObservable { Observable.defer { Observable.fromIterable(treatmentsPlugin.service.treatmentData) } }
.map { enqueueTreatment(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allBgReadings) })
.andThen(Observable.defer { Observable.fromIterable(repository.compatGetBgReadingsDataFromTime(0, true).blockingGet()) })
.map { enqueueBGReading(it); increaseCounter() }
.ignoreElements()
.andThen(Observable.defer { Observable.fromIterable(MainApp.getDbHelper().allCareportalEvents) })
@ -401,7 +406,7 @@ class OpenHumansUploader @Inject constructor(
wakeLock.release()
}
.onErrorComplete()
.subscribeOn(Schedulers.io())
.subscribeOn(aapsSchedulers.io)
.subscribe()
}

View file

@ -28,6 +28,7 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.OverviewFragmentBinding
import info.nightscout.androidaps.dialogs.*
import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.interfaces.*
@ -55,21 +56,15 @@ import info.nightscout.androidaps.skins.SkinProvider
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.extensions.directionToIcon
import info.nightscout.androidaps.utils.extensions.toVisibility
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.ui.UIRunnable
import info.nightscout.androidaps.utils.wizard.QuickWizard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.overview_buttons_layout.*
import kotlinx.android.synthetic.main.overview_fragment.*
import kotlinx.android.synthetic.main.overview_graphs_layout.*
import kotlinx.android.synthetic.main.overview_info_layout.*
import kotlinx.android.synthetic.main.overview_loop_pumpstatus_layout.*
import kotlinx.android.synthetic.main.overview_statuslights_layout.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -85,6 +80,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var sp: SP
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@ -99,6 +95,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
@Inject lateinit var dexcomPlugin: DexcomPlugin
@Inject lateinit var dexcomMediator: DexcomPlugin.DexcomMediator
@Inject lateinit var xdripPlugin: XdripPlugin
@Inject lateinit var notificationStore: NotificationStore
@Inject lateinit var actionStringHandler: ActionStringHandler
@ -130,15 +127,19 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private val graphLock = Object()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
private var _binding: OverviewFragmentBinding? = null
//check screen width
dm = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
return inflater.inflate(R.layout.overview_fragment, container, false)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
OverviewFragmentBinding.inflate(inflater, container, false).also {
_binding = it
//check screen width
dm = DisplayMetrics()
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
}.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -151,25 +152,25 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val landscape = screenHeight < screenWidth
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, view, landscape, resourceHelper.gb(R.bool.isTablet), smallHeight)
nsclient_layout?.visibility = config.NSCLIENT.toVisibility()
binding.nsclientLayout.visibility = config.NSCLIENT.toVisibility()
overview_pumpstatus?.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder))
binding.loopPumpStatusLayout.pumpStatus.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder))
overview_notifications?.setHasFixedSize(false)
overview_notifications?.layoutManager = LinearLayoutManager(view.context)
binding.notifications.setHasFixedSize(false)
binding.notifications.layoutManager = LinearLayoutManager(view.context)
axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
overview_bggraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
overview_bggraph?.gridLabelRenderer?.reloadStyles()
overview_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
overview_bggraph?.layoutParams?.height = resourceHelper.dpToPx(skinProvider.activeSkin().mainGraphHeight)
binding.graphsLayout.bgGraph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
binding.graphsLayout.bgGraph.gridLabelRenderer?.reloadStyles()
binding.graphsLayout.bgGraph.gridLabelRenderer?.labelVerticalWidth = axisWidth
binding.graphsLayout.bgGraph.layoutParams?.height = resourceHelper.dpToPx(skinProvider.activeSkin().mainGraphHeight)
carbAnimation = overview_carbs_icon?.background as AnimationDrawable?
carbAnimation = binding.infoLayout.carbsIcon.background as AnimationDrawable?
carbAnimation?.setEnterFadeDuration(1200)
carbAnimation?.setExitFadeDuration(1200)
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
overview_bggraph?.setOnLongClickListener {
binding.graphsLayout.bgGraph.setOnLongClickListener {
rangeToDisplay += 6
rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay
sp.putInt(R.string.key_rangetodisplay, rangeToDisplay)
@ -178,93 +179,95 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
false
}
prepareGraphsIfNeeded(overviewMenus.setting.size)
overviewMenus.setupChartMenu(overview_chartMenuButton)
overviewMenus.setupChartMenu(binding.graphsLayout.chartMenuButton)
overview_activeprofile?.setOnClickListener(this)
overview_activeprofile?.setOnLongClickListener(this)
overview_temptarget?.setOnClickListener(this)
overview_temptarget?.setOnLongClickListener(this)
overview_accepttempbutton?.setOnClickListener(this)
overview_treatmentbutton?.setOnClickListener(this)
overview_wizardbutton?.setOnClickListener(this)
overview_calibrationbutton?.setOnClickListener(this)
overview_cgmbutton?.setOnClickListener(this)
overview_insulinbutton?.setOnClickListener(this)
overview_carbsbutton?.setOnClickListener(this)
overview_quickwizardbutton?.setOnClickListener(this)
overview_quickwizardbutton?.setOnLongClickListener(this)
overview_apsmode?.setOnClickListener(this)
overview_apsmode?.setOnLongClickListener(this)
overview_activeprofile?.setOnLongClickListener(this)
binding.loopPumpStatusLayout.activeProfile.setOnClickListener(this)
binding.loopPumpStatusLayout.activeProfile.setOnLongClickListener(this)
binding.loopPumpStatusLayout.tempTarget.setOnClickListener(this)
binding.loopPumpStatusLayout.tempTarget.setOnLongClickListener(this)
binding.buttonsLayout.acceptTempButton.setOnClickListener(this)
binding.buttonsLayout.treatmentButton.setOnClickListener(this)
binding.buttonsLayout.wizardButton.setOnClickListener(this)
binding.buttonsLayout.calibrationButton.setOnClickListener(this)
binding.buttonsLayout.cgmButton.setOnClickListener(this)
binding.buttonsLayout.insulinButton.setOnClickListener(this)
binding.buttonsLayout.carbsButton.setOnClickListener(this)
binding.buttonsLayout.quickWizardButton.setOnClickListener(this)
binding.buttonsLayout.quickWizardButton.setOnLongClickListener(this)
binding.infoLayout.apsMode.setOnClickListener(this)
binding.infoLayout.apsMode.setOnLongClickListener(this)
binding.loopPumpStatusLayout.activeProfile.setOnLongClickListener(this)
}
@Synchronized
override fun onPause() {
super.onPause()
disposable.clear()
loopHandler.removeCallbacksAndMessages(null)
}
@Synchronized
override fun onResume() {
super.onResume()
disposable.add(rxBus
.toObservable(EventRefreshOverview::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
if (it.now) updateGUI(it.from)
else scheduleUpdateGUI(it.from)
}) { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventExtendedBolusChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventExtendedBolusChange") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventExtendedBolusChange") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTempBasalChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventTempBasalChange") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventTempBasalChange") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTreatmentChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventTreatmentChange") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventTreatmentChange") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTempTargetChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventTempTargetChange") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventTempTargetChange") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventAcceptOpenLoopChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventCareportalEventChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventInitializationChanged::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventInitializationChanged") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventInitializationChanged") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventAutosensCalculationFinished") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventAutosensCalculationFinished") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventProfileNeedsUpdate::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventProfileNeedsUpdate") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventProfileNeedsUpdate") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventPreferenceChange") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventPreferenceChange") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventNewOpenLoopNotification::class.java)
.observeOn(Schedulers.io())
.subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventPumpStatusChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updatePumpStatus(it) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updatePumpStatus(it) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventIobCalculationProgress::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ overview_iobcalculationprogess?.text = it.progress }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ binding.graphsLayout.iobCalculationProgress.text = it.progress }, fabricPrivacy::logException))
refreshLoop = Runnable {
scheduleUpdateGUI("refreshLoop")
@ -275,20 +278,26 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
updateGUI("onResume")
}
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onClick(v: View) {
// try to fix https://fabric.io/nightscout3/android/apps/info.nightscout.androidaps/issues/5aca7a1536c7b23527eb4be7?time=last-seven-days
// https://stackoverflow.com/questions/14860239/checking-if-state-is-saved-before-committing-a-fragmenttransaction
if (childFragmentManager.isStateSaved) return
activity?.let { activity ->
when (v.id) {
R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) TreatmentDialog().show(childFragmentManager, "Overview") })
R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) WizardDialog().show(childFragmentManager, "Overview") })
R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) InsulinDialog().show(childFragmentManager, "Overview") })
R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) onClickQuickWizard() })
R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) CarbsDialog().show(childFragmentManager, "Overview") })
R.id.overview_temptarget -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if(isAdded) TempTargetDialog().show(childFragmentManager, "Overview") })
R.id.treatment_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TreatmentDialog().show(childFragmentManager, "Overview") })
R.id.wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) WizardDialog().show(childFragmentManager, "Overview") })
R.id.insulin_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) InsulinDialog().show(childFragmentManager, "Overview") })
R.id.quick_wizard_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) onClickQuickWizard() })
R.id.carbs_button -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) CarbsDialog().show(childFragmentManager, "Overview") })
R.id.temp_target -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { if (isAdded) TempTargetDialog().show(childFragmentManager, "Overview") })
R.id.overview_activeprofile -> {
R.id.active_profile -> {
ProfileViewerDialog().also { pvd ->
pvd.arguments = Bundle().also {
it.putLong("time", DateUtil.now())
@ -297,23 +306,23 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}.show(childFragmentManager, "ProfileViewDialog")
}
R.id.overview_cgmbutton -> {
R.id.cgm_button -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE))
openCgmApp("com.eveningoutpost.dexdrip")
else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
dexcomPlugin.findDexcomPackageName()?.let {
dexcomMediator.findDexcomPackageName()?.let {
openCgmApp(it)
}
?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed))
}
}
R.id.overview_calibrationbutton -> {
R.id.calibration_button -> {
if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) {
CalibrationDialog().show(childFragmentManager, "CalibrationDialog")
} else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) {
try {
dexcomPlugin.findDexcomPackageName()?.let {
dexcomMediator.findDexcomPackageName()?.let {
startActivity(Intent("com.dexcom.cgm.activities.MeterEntryActivity").setPackage(it))
}
?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed))
@ -323,7 +332,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
}
R.id.overview_accepttempbutton -> {
R.id.accept_temp_button -> {
profileFunction.getProfile() ?: return
if (loopPlugin.isEnabled(PluginType.LOOP)) {
val lastRun = loopPlugin.lastRun
@ -333,7 +342,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.tempbasal_label), lastRun.constraintsProcessed?.toSpanned()
?: "".toSpanned(), {
aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL")
overview_accepttempbutton?.visibility = View.GONE
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID)
actionStringHandler.handleInitiate("cancelChangeRequest")
loopPlugin.acceptChangeRequest()
@ -343,9 +352,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
}
R.id.overview_apsmode -> {
R.id.aps_mode -> {
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
if(isAdded) LoopDialog().also { dialog ->
if (isAdded) LoopDialog().also { dialog ->
dialog.arguments = Bundle().also { it.putInt("showOkCancel", 1) }
}.show(childFragmentManager, "Overview")
})
@ -370,12 +379,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
override fun onLongClick(v: View): Boolean {
when (v.id) {
R.id.overview_quickwizardbutton -> {
R.id.quick_wizard_button -> {
startActivity(Intent(v.context, QuickWizardListActivity::class.java))
return true
}
R.id.overview_apsmode -> {
R.id.aps_mode -> {
activity?.let { activity ->
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable {
LoopDialog().also { dialog ->
@ -385,8 +394,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
}
R.id.overview_temptarget -> v.performClick()
R.id.overview_activeprofile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
R.id.temp_target -> v.performClick()
R.id.active_profile -> activity?.let { activity -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, UIRunnable { ProfileSwitchDialog().show(childFragmentManager, "Overview") }) }
}
return false
@ -399,7 +408,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
val pump = activePlugin.activePump
val quickWizardEntry = quickWizard.getActive()
if (quickWizardEntry != null && actualBg != null && profile != null) {
overview_quickwizardbutton?.visibility = View.VISIBLE
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) {
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
@ -417,12 +426,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private fun updatePumpStatus(event: EventPumpStatusChanged) {
val status = event.getStatus(resourceHelper)
if (status != "") {
overview_pumpstatus?.text = status
overview_pumpstatuslayout?.visibility = View.VISIBLE
overview_looplayout?.visibility = View.GONE
binding.loopPumpStatusLayout.pumpStatus.text = status
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.VISIBLE
binding.loopPumpStatusLayout.loopLayout.visibility = View.GONE
} else {
overview_pumpstatuslayout?.visibility = View.GONE
overview_looplayout?.visibility = View.VISIBLE
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.GONE
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
}
}
@ -437,12 +446,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// QuickWizard button
val quickWizardEntry = quickWizard.getActive()
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized && !pump.isSuspended) {
overview_quickwizardbutton?.visibility = View.VISIBLE
binding.buttonsLayout.quickWizardButton.visibility = View.VISIBLE
val wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false)
overview_quickwizardbutton?.text = quickWizardEntry.buttonText() + "\n" + resourceHelper.gs(R.string.format_carbs, quickWizardEntry.carbs()) +
binding.buttonsLayout.quickWizardButton.text = quickWizardEntry.buttonText() + "\n" + resourceHelper.gs(R.string.format_carbs, quickWizardEntry.carbs()) +
" " + resourceHelper.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin)
if (wizard.calculatedTotalInsulin <= 0) overview_quickwizardbutton?.visibility = View.GONE
} else overview_quickwizardbutton?.visibility = View.GONE
if (wizard.calculatedTotalInsulin <= 0) binding.buttonsLayout.quickWizardButton.visibility = View.GONE
} else binding.buttonsLayout.quickWizardButton.visibility = View.GONE
// **** Temp button ****
val lastRun = loopPlugin.lastRun
@ -454,23 +463,23 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
lastRun.constraintsProcessed?.isChangeRequested == true // change is requested
if (showAcceptButton && pump.isInitialized && !pump.isSuspended && loopPlugin.isEnabled(PluginType.LOOP)) {
overview_accepttempbutton?.visibility = View.VISIBLE
overview_accepttempbutton?.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
binding.buttonsLayout.acceptTempButton.visibility = View.VISIBLE
binding.buttonsLayout.acceptTempButton.text = "${resourceHelper.gs(R.string.setbasalquestion)}\n${lastRun!!.constraintsProcessed}"
} else {
overview_accepttempbutton?.visibility = View.GONE
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
}
// **** Various treatment buttons ****
overview_carbsbutton?.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized && !pump.isSuspended) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
overview_treatmentbutton?.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
overview_wizardbutton?.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
overview_insulinbutton?.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
binding.buttonsLayout.carbsButton.visibility = ((!activePlugin.activePump.pumpDescription.storesCarbInfo || pump.isInitialized && !pump.isSuspended) && profile != null && sp.getBoolean(R.string.key_show_carbs_button, true)).toVisibility()
binding.buttonsLayout.treatmentButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_treatment_button, false)).toVisibility()
binding.buttonsLayout.wizardButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_wizard_button, true)).toVisibility()
binding.buttonsLayout.insulinButton.visibility = (pump.isInitialized && !pump.isSuspended && profile != null && sp.getBoolean(R.string.key_show_insulin_button, true)).toVisibility()
// **** Calibration & CGM buttons ****
val xDripIsBgSource = xdripPlugin.isEnabled(PluginType.BGSOURCE)
val dexcomIsSource = dexcomPlugin.isEnabled(PluginType.BGSOURCE)
overview_calibrationbutton?.visibility = ((xDripIsBgSource || dexcomIsSource) && actualBG != null && sp.getBoolean(R.string.key_show_calibration_button, true)).toVisibility()
overview_cgmbutton?.visibility = (sp.getBoolean(R.string.key_show_cgm_button, false) && (xDripIsBgSource || dexcomIsSource)).toVisibility()
binding.buttonsLayout.calibrationButton.visibility = ((xDripIsBgSource || dexcomIsSource) && actualBG != null && sp.getBoolean(R.string.key_show_calibration_button, true)).toVisibility()
binding.buttonsLayout.cgmButton.visibility = (sp.getBoolean(R.string.key_show_cgm_button, false) && (xDripIsBgSource || dexcomIsSource)).toVisibility()
}
@ -481,7 +490,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
// rebuild needed
secondaryGraphs.clear()
secondaryGraphsLabel.clear()
overview_iobgraph.removeAllViews()
binding.graphsLayout.iobGraph.removeAllViews()
for (i in 1 until numOfGraphs) {
val relativeLayout = RelativeLayout(context)
relativeLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
@ -504,7 +513,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
relativeLayout.addView(label)
secondaryGraphsLabel.add(label)
overview_iobgraph.addView(relativeLayout)
binding.graphsLayout.iobGraph.addView(relativeLayout)
secondaryGraphs.add(graph)
}
}
@ -528,19 +537,20 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
@SuppressLint("SetTextI18n")
fun updateGUI(from: String) {
if (_binding == null) return
aapsLogger.debug("UpdateGUI from $from")
overview_time?.text = dateUtil.timeString(Date())
binding.infoLayout.time.text = dateUtil.timeString(Date())
if (!profileFunction.isProfileValid("Overview")) {
overview_pumpstatus?.setText(R.string.noprofileset)
overview_pumpstatuslayout?.visibility = View.VISIBLE
overview_looplayout?.visibility = View.GONE
binding.loopPumpStatusLayout.pumpStatus.setText(R.string.noprofileset)
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.VISIBLE
binding.loopPumpStatusLayout.loopLayout.visibility = View.GONE
return
}
overview_notifications?.let { notificationStore.updateNotifications(it) }
overview_pumpstatuslayout?.visibility = View.GONE
overview_looplayout?.visibility = View.VISIBLE
binding.notifications.let { notificationStore.updateNotifications(it) }
binding.loopPumpStatusLayout.pumpStatusLayout.visibility = View.GONE
binding.loopPumpStatusLayout.loopLayout.visibility = View.VISIBLE
val profile = profileFunction.getProfile() ?: return
val actualBG = iobCobCalculatorPlugin.actualBg()
@ -567,126 +577,126 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
else -> resourceHelper.gc(R.color.inrange)
}
overview_bg?.text = lastBG.valueToUnitsToString(units)
overview_bg?.setTextColor(color)
overview_arrow?.setImageResource(lastBG.directionToIcon(databaseHelper))
overview_arrow?.setColorFilter(color)
binding.infoLayout.bg.text = lastBG.valueToUnitsString(units)
binding.infoLayout.bg.setTextColor(color)
binding.infoLayout.arrow.setImageResource(lastBG.trendArrow.directionToIcon())
binding.infoLayout.arrow.setColorFilter(color)
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (glucoseStatus != null) {
overview_delta_large?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
overview_delta_large?.setTextColor(color)
overview_delta?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
overview_avgdelta?.text = "${Profile.toSignedUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)}"
overview_long_avgdelta?.text = "${Profile.toSignedUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)}"
binding.infoLayout.deltaLarge.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
binding.infoLayout.deltaLarge.setTextColor(color)
binding.infoLayout.delta.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
binding.infoLayout.avgDelta.text = Profile.toSignedUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)
binding.infoLayout.longAvgDelta.text = Profile.toSignedUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)
} else {
overview_delta?.text = "Δ " + resourceHelper.gs(R.string.notavailable)
overview_avgdelta?.text = ""
overview_long_avgdelta?.text = ""
binding.infoLayout.delta.text = "Δ " + resourceHelper.gs(R.string.notavailable)
binding.infoLayout.avgDelta.text = ""
binding.infoLayout.longAvgDelta.text = ""
}
// strike through if BG is old
overview_bg?.let { overview_bg ->
binding.infoLayout.bg.let { overview_bg ->
var flag = overview_bg.paintFlags
flag = if (actualBG == null) {
flag or Paint.STRIKE_THRU_TEXT_FLAG
} else flag and Paint.STRIKE_THRU_TEXT_FLAG.inv()
overview_bg.paintFlags = flag
}
overview_timeago?.text = DateUtil.minAgo(resourceHelper, lastBG.date)
overview_timeagoshort?.text = "(" + DateUtil.minAgoShort(lastBG.date) + ")"
binding.infoLayout.timeAgo.text = DateUtil.minAgo(resourceHelper, lastBG.timestamp)
binding.infoLayout.timeAgoShort.text = "(" + DateUtil.minAgoShort(lastBG.timestamp) + ")"
}
val closedLoopEnabled = constraintChecker.isClosedLoopAllowed()
// aps mode
if (config.APS && pump.pumpDescription.isTempBasalCapable) {
overview_apsmode?.visibility = View.VISIBLE
overview_time_llayout?.visibility = View.GONE
binding.infoLayout.apsMode.visibility = View.VISIBLE
binding.infoLayout.timeLayout.visibility = View.GONE
when {
loopPlugin.isEnabled() && loopPlugin.isSuperBolus -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_superbolus)
overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
overview_apsmode_text?.visibility = View.VISIBLE
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_superbolus)
binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
loopPlugin.isDisconnected -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_disconnected)
overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
overview_apsmode_text?.visibility = View.VISIBLE
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_disconnected)
binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
loopPlugin.isEnabled() && loopPlugin.isSuspended -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_paused)
overview_apsmode_text?.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
overview_apsmode_text?.visibility = View.VISIBLE
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_paused)
binding.infoLayout.apsModeText.text = DateUtil.age(loopPlugin.minutesToEndOfSuspend() * 60000L, true, resourceHelper)
binding.infoLayout.apsModeText.visibility = View.VISIBLE
}
pump.isSuspended -> {
overview_apsmode?.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Insulet_Omnipod) {
binding.infoLayout.apsMode.setImageResource(if (pump.pumpDescription.pumpType == PumpType.Insulet_Omnipod) {
// For Omnipod, indicate the pump as disconnected when it's suspended.
// The only way to 'reconnect' it, is through the Omnipod tab
R.drawable.ic_loop_disconnected
} else {
R.drawable.ic_loop_paused
})
overview_apsmode_text?.visibility = View.GONE
binding.infoLayout.apsModeText.visibility = View.GONE
}
loopPlugin.isEnabled() && closedLoopEnabled.value() && loopPlugin.isLGS -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_lgs)
overview_apsmode_text?.visibility = View.GONE
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_lgs)
binding.infoLayout.apsModeText.visibility = View.GONE
}
loopPlugin.isEnabled() && closedLoopEnabled.value() -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_closed)
overview_apsmode_text?.visibility = View.GONE
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_closed)
binding.infoLayout.apsModeText.visibility = View.GONE
}
loopPlugin.isEnabled() && !closedLoopEnabled.value() -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_open)
overview_apsmode_text?.visibility = View.GONE
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_open)
binding.infoLayout.apsModeText.visibility = View.GONE
}
else -> {
overview_apsmode?.setImageResource(R.drawable.ic_loop_disabled)
overview_apsmode_text?.visibility = View.GONE
binding.infoLayout.apsMode.setImageResource(R.drawable.ic_loop_disabled)
binding.infoLayout.apsModeText.visibility = View.GONE
}
}
} else {
//nsclient
overview_apsmode?.visibility = View.GONE
overview_apsmode_text?.visibility = View.GONE
overview_time_llayout?.visibility = View.VISIBLE
binding.infoLayout.apsMode.visibility = View.GONE
binding.infoLayout.apsModeText.visibility = View.GONE
binding.infoLayout.timeLayout.visibility = View.VISIBLE
}
// temp target
val tempTarget = treatmentsPlugin.tempTargetFromHistory
if (tempTarget != null) {
overview_temptarget?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
overview_temptarget?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
overview_temptarget?.text = Profile.toTargetRangeString(tempTarget.low, tempTarget.high, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.end(), resourceHelper)
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(tempTarget.low, tempTarget.high, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.end(), resourceHelper)
} else {
// If the target is not the same as set in the profile then oref has overridden it
val targetUsed = lastRun?.constraintsProcessed?.targetBG ?: 0.0
if (targetUsed != 0.0 && abs(profile.targetMgdl - targetUsed) > 0.01) {
aapsLogger.debug("Adjusted target. Profile: ${profile.targetMgdl} APS: $targetUsed")
overview_temptarget?.text = Profile.toTargetRangeString(targetUsed, targetUsed, Constants.MGDL, units)
overview_temptarget?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
overview_temptarget?.setBackgroundColor(resourceHelper.gc(R.color.tempTargetBackground))
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(targetUsed, targetUsed, Constants.MGDL, units)
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.tempTargetBackground))
} else {
overview_temptarget?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
overview_temptarget?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
overview_temptarget?.text = Profile.toTargetRangeString(profile.targetLowMgdl, profile.targetHighMgdl, Constants.MGDL, units)
binding.loopPumpStatusLayout.tempTarget.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
binding.loopPumpStatusLayout.tempTarget.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
binding.loopPumpStatusLayout.tempTarget.text = Profile.toTargetRangeString(profile.targetLowMgdl, profile.targetHighMgdl, Constants.MGDL, units)
}
}
// Basal, TBR
val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis())
overview_basebasal?.text = activeTemp?.let { "T:" + activeTemp.toStringVeryShort() }
binding.infoLayout.baseBasal.text = activeTemp?.let { "T:" + activeTemp.toStringVeryShort() }
?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)
overview_basal_llayout?.setOnClickListener {
binding.infoLayout.basalLayout.setOnClickListener {
var fullText = "${resourceHelper.gs(R.string.basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}"
if (activeTemp != null)
fullText += "\n" + resourceHelper.gs(R.string.tempbasal_label) + ": " + activeTemp.toStringFull()
@ -694,36 +704,36 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText)
}
}
overview_basebasal?.setTextColor(activeTemp?.let { resourceHelper.gc(R.color.basal) }
binding.infoLayout.baseBasal.setTextColor(activeTemp?.let { resourceHelper.gc(R.color.basal) }
?: resourceHelper.gc(R.color.defaulttextcolor))
overview_basebasal_icon?.setImageResource(R.drawable.ic_cp_basal_no_tbr)
binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_no_tbr)
val percentRate = activeTemp?.tempBasalConvertedToPercent(System.currentTimeMillis(), profile)
?: 100
if (percentRate > 100) overview_basebasal_icon?.setImageResource(R.drawable.ic_cp_basal_tbr_high)
if (percentRate < 100) overview_basebasal_icon?.setImageResource(R.drawable.ic_cp_basal_tbr_low)
if (percentRate > 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_high)
if (percentRate < 100) binding.infoLayout.baseBasalIcon.setImageResource(R.drawable.ic_cp_basal_tbr_low)
// Extended bolus
val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis())
overview_extendedbolus?.text =
binding.infoLayout.extendedBolus.text =
if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses)
resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate())
else ""
overview_extendedbolus?.setOnClickListener {
binding.infoLayout.extendedBolus.setOnClickListener {
if (extendedBolus != null) activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString())
}
}
overview_extended_llayout?.visibility = (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
binding.infoLayout.extendedLayout.visibility = (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()
// Active profile
overview_activeprofile?.text = profileFunction.getProfileNameWithDuration()
binding.loopPumpStatusLayout.activeProfile.text = profileFunction.getProfileNameWithDuration()
if (profile.percentage != 100 || profile.timeshift != 0) {
overview_activeprofile?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
overview_activeprofile?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning))
binding.loopPumpStatusLayout.activeProfile.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning))
} else {
overview_activeprofile?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
overview_activeprofile?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
binding.loopPumpStatusLayout.activeProfile.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault))
binding.loopPumpStatusLayout.activeProfile.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault))
}
processButtonsVisibility()
@ -733,9 +743,9 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
treatmentsPlugin.updateTotalIOBTempBasals()
val bolusIob = treatmentsPlugin.lastCalculationTreatments.round()
val basalIob = treatmentsPlugin.lastCalculationTempBasals.round()
overview_iob?.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
binding.infoLayout.iob.text = resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob)
overview_iob_llayout?.setOnClickListener {
binding.infoLayout.iobLayout.setOnClickListener {
activity?.let {
OKDialog.show(it, resourceHelper.gs(R.string.iob),
resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" +
@ -746,8 +756,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
}
// Status lights
overview_statuslights?.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
statusLightHandler.updateStatusLights(careportal_canulaage, careportal_insulinage, careportal_reservoirlevel, careportal_sensorage, null, careportal_pbage, careportal_batterylevel)
binding.statusLightsLayout.statusLights.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
statusLightHandler.updateStatusLights(binding.statusLightsLayout.cannulaAge, binding.statusLightsLayout.insulinAge, binding.statusLightsLayout.reservoirLevel, binding.statusLightsLayout.sensorAge, null, binding.statusLightsLayout.pbAge, binding.statusLightsLayout.batteryLevel)
// cob
var cobText: String = resourceHelper.gs(R.string.value_unavailable_short)
@ -763,36 +773,36 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (treatmentsPlugin.lastCarbTime < lastRun.lastAPSRun) {
cobText = cobText + " | " + lastRun.constraintsProcessed!!.carbsReq + " " + resourceHelper.gs(R.string.required)
}
overview_cob?.text = cobText
binding.infoLayout.cob.text = cobText
if (carbAnimation?.isRunning == false)
carbAnimation?.start()
} else {
overview_cob?.text = cobText
binding.infoLayout.cob.text = cobText
carbAnimation?.stop()
carbAnimation?.selectDrawable(0)
}
} else overview_cob?.text = cobText
} else binding.infoLayout.cob.text = cobText
// pump status from ns
overview_pump?.text = nsDeviceStatus.pumpStatus
overview_pump?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.pump), nsDeviceStatus.extendedPumpStatus) } }
binding.pump.text = nsDeviceStatus.pumpStatus
binding.pump.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.pump), nsDeviceStatus.extendedPumpStatus) } }
// OpenAPS status from ns
overview_openaps?.text = nsDeviceStatus.openApsStatus
overview_openaps?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.openaps), nsDeviceStatus.extendedOpenApsStatus) } }
binding.openaps.text = nsDeviceStatus.openApsStatus
binding.openaps.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.openaps), nsDeviceStatus.extendedOpenApsStatus) } }
// Uploader status from ns
overview_uploader?.text = nsDeviceStatus.uploaderStatusSpanned
overview_uploader?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } }
binding.uploader.text = nsDeviceStatus.uploaderStatusSpanned
binding.uploader.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } }
// Sensitivity
if (sp.getBoolean(R.string.key_openapsama_useautosens, false) && constraintChecker.isAutosensModeEnabled().value()) {
overview_sensitivity_icon?.setImageResource(R.drawable.ic_swap_vert_black_48dp_green)
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_swap_vert_black_48dp_green)
} else {
overview_sensitivity_icon?.setImageResource(R.drawable.ic_x_swap_vert)
binding.infoLayout.sensitivityIcon.setImageResource(R.drawable.ic_x_swap_vert)
}
overview_sensitivity?.text =
binding.infoLayout.sensitivity.text =
iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData ->
String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)
} ?: ""
@ -800,10 +810,10 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private fun updateGraph(lastRun: LoopInterface.LastRun?, predictionsAvailable: Boolean, lowLine: Double, highLine: Double, pump: PumpInterface, profile: Profile) {
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
overview_bggraph ?: return@launch
if (_binding == null) return@launch
val menuChartSettings = overviewMenus.setting
prepareGraphsIfNeeded(menuChartSettings.size)
val graphData = GraphData(injector, overview_bggraph, iobCobCalculatorPlugin, treatmentsPlugin)
val graphData = GraphData(injector, binding.graphsLayout.bgGraph, iobCobCalculatorPlugin, treatmentsPlugin)
val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
// do preparation in different thread
@ -877,23 +887,25 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
var useDevForScale = false
var useRatioForScale = false
var useDSForScale = false
var useIAForScale = false
var useBGIForScale = false
when {
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
}
var alignIobScale = menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]
var alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
if (menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal]) secondGraphData.addAbsIob(fromTime, now, useABSForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal])
if (menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, menuChartSettings[g + 1][OverviewMenus.CharType.PRE.ordinal], alignIobScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0, alignDevBgiScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
if (menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8)
if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(fromTime, endTime, useBGIForScale, if(alignDevBgiScale) 1.0 else 0.8, alignDevBgiScale)
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
// set manual x bounds to have nice steps
@ -914,7 +926,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
menuChartSettings[g + 1][OverviewMenus.CharType.COB.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] ||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
).toVisibility()
secondaryGraphsData[g].performUpdate()

View file

@ -40,7 +40,8 @@ class OverviewMenus @Inject constructor(
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true,shortnameId = R.string.cob),
DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true,shortnameId = R.string.deviation_shortname),
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true,shortnameId = R.string.sensitivity_shortname),
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = true,shortnameId = R.string.activity_shortname),
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = false,shortnameId = R.string.activity_shortname),
BGI(R.string.overview_show_bgi, R.color.bgi, primary = false, secondary = true,shortnameId = R.string.bgi_shortname),
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true,shortnameId = R.string.devslope_shortname)
}

View file

@ -16,12 +16,11 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNo
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.extensions.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@ -34,6 +33,7 @@ class OverviewPlugin @Inject constructor(
private val rxBus: RxBusWrapper,
private val sp: SP,
aapsLogger: AAPSLogger,
private val aapsSchedulers: AapsSchedulers,
resourceHelper: ResourceHelper,
private val config: Config
) : PluginBase(PluginDescription()
@ -56,18 +56,18 @@ class OverviewPlugin @Inject constructor(
notificationStore.createNotificationChannel()
disposable += rxBus
.toObservable(EventNewNotification::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ n ->
if (notificationStore.add(n.notification))
rxBus.send(EventRefreshOverview("EventNewNotification"))
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventDismissNotification::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ n ->
if (notificationStore.remove(n.id))
rxBus.send(EventRefreshOverview("EventDismissNotification"))
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
}
override fun onStop() {

View file

@ -9,8 +9,8 @@ import info.nightscout.androidaps.R
import info.nightscout.androidaps.db.CareportalEvent
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.OmnipodConstants
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors
import info.nightscout.androidaps.utils.resources.ResourceHelper
@ -52,7 +52,7 @@ class StatusLightHandler @Inject constructor(
}
if (!config.NSCLIENT) {
if (pump.model() == PumpType.Insulet_Omnipod && pump is OmnipodPumpPlugin) { // instance of check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below
if (pump.model() == PumpType.Insulet_Omnipod && pump is OmnipodErosPumpPlugin) { // instance of check is needed because at startup, pump can still be VirtualPumpPlugin and that will cause a crash because of the class cast below
handleOmnipodBatteryLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%", pump.isUseRileyLinkBatteryLevel)
} else if (pump.model() != PumpType.AccuChekCombo) {
handleLevel(careportal_battery_level, R.string.key_statuslights_bat_critical, 26.0, R.string.key_statuslights_bat_warning, 51.0, pump.batteryLevel.toDouble(), "%")

View file

@ -18,13 +18,14 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWiza
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.wizard.QuickWizard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject
class QuickWizardListActivity : NoSplashAppCompatActivity() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var quickWizard: QuickWizard
@ -95,11 +96,11 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
super.onResume()
disposable += rxBus
.toObservable(EventQuickWizardChange::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
val adapter = RecyclerViewAdapter(supportFragmentManager)
binding.recyclerview.swapAdapter(adapter, false)
}, { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException)
}
override fun onPause() {

View file

@ -1,29 +1,31 @@
package info.nightscout.androidaps.plugins.general.overview.dialogs
import android.app.TimePickerDialog
import android.os.Bundle
import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import android.widget.AdapterView
import android.widget.ArrayAdapter
import dagger.android.support.DaggerDialogFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
import info.nightscout.androidaps.databinding.OverviewEditquickwizardDialogBinding
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventQuickWizardChange
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.SafeParse
import kotlinx.android.synthetic.main.okcancel.*
import kotlinx.android.synthetic.main.overview_editquickwizard_dialog.*
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.extensions.selectedItemPosition
import info.nightscout.androidaps.utils.extensions.setEnableForChildren
import info.nightscout.androidaps.utils.extensions.setSelection
import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
import org.json.JSONException
import java.util.*
import javax.inject.Inject
class EditQuickWizardDialog : DaggerDialogFragment() {
class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var quickWizard: QuickWizard
@ -31,37 +33,43 @@ class EditQuickWizardDialog : DaggerDialogFragment() {
var position = -1
var fromSeconds: Int = 0
var toSeconds: Int = 0
private var _binding: OverviewEditquickwizardDialogBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
savedInstanceState: Bundle?): View {
dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
isCancelable = true
dialog?.setCanceledOnTouchOutside(false)
return inflater.inflate(R.layout.overview_editquickwizard_dialog, container, false)
_binding = OverviewEditquickwizardDialogBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
(arguments ?: savedInstanceState)?.let { bundle ->
position = bundle.getInt("position", -1)
}
val entry = if (position ==-1) quickWizard.newEmptyItem() else quickWizard[position]
ok.setOnClickListener {
if (overview_editquickwizard_from_spinner.selectedItem == null) return@setOnClickListener
if (overview_editquickwizard_to_spinner.selectedItem == null) return@setOnClickListener
val entry = if (position == -1) quickWizard.newEmptyItem() else quickWizard[position]
binding.okcancel.ok.setOnClickListener {
try {
entry.storage.put("buttonText", overview_editquickwizard_button_edit.text.toString())
entry.storage.put("carbs", SafeParse.stringToInt(overview_editquickwizard_carbs_edit.text.toString()))
val validFromInt = DateUtil.toSeconds(overview_editquickwizard_from_spinner.selectedItem.toString())
entry.storage.put("validFrom", validFromInt)
val validToInt = DateUtil.toSeconds(overview_editquickwizard_to_spinner.selectedItem.toString())
entry.storage.put("validTo", validToInt)
entry.storage.put("useBG", overview_editquickwizard_usebg_spinner.selectedItemPosition)
entry.storage.put("useCOB", overview_editquickwizard_usecob_spinner.selectedItemPosition)
entry.storage.put("useBolusIOB", overview_editquickwizard_usebolusiob_spinner.selectedItemPosition)
entry.storage.put("useBasalIOB", overview_editquickwizard_usebasaliob_spinner.selectedItemPosition)
entry.storage.put("useTrend", overview_editquickwizard_usetrend_spinner.selectedItemPosition)
entry.storage.put("useSuperBolus", overview_editquickwizard_usesuperbolus_spinner.selectedItemPosition)
entry.storage.put("useTempTarget", overview_editquickwizard_usetemptarget_spinner.selectedItemPosition)
entry.storage.put("buttonText", binding.buttonEdit.text.toString())
entry.storage.put("carbs", SafeParse.stringToInt(binding.carbsEdit.text.toString()))
entry.storage.put("validFrom", fromSeconds)
entry.storage.put("validTo", toSeconds)
entry.storage.put("useBG", binding.useBg.selectedItemPosition)
entry.storage.put("useCOB", binding.useCob.selectedItemPosition)
entry.storage.put("useBolusIOB", binding.useBolusIob.selectedItemPosition)
entry.storage.put("useBasalIOB", binding.useBasalIob.selectedItemPosition)
entry.storage.put("useTrend", binding.useTrend.selectedItemPosition)
entry.storage.put("useSuperBolus", binding.useSuperBolus.selectedItemPosition)
entry.storage.put("useTempTarget", binding.useTempTarget.selectedItemPosition)
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
@ -70,43 +78,60 @@ class EditQuickWizardDialog : DaggerDialogFragment() {
rxBus.send(EventQuickWizardChange())
dismiss()
}
cancel.setOnClickListener { dismiss() }
binding.okcancel.cancel.setOnClickListener { dismiss() }
var posFrom = 0
var posTo = 95
val timeList = ArrayList<CharSequence>()
var pos = 0
var t = 0
while (t < 24 * 60 * 60) {
timeList.add(dateUtil.timeString(DateUtil.toDate(t)))
if (entry.validFrom() == t) posFrom = pos
if (entry.validTo() == t) posTo = pos
pos++
t += 15 * 60
// create an OnTimeSetListener
val fromTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
fromSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt()
binding.from.text = dateUtil.timeString(DateUtil.toDate(fromSeconds))
}
timeList.add(dateUtil.timeString(DateUtil.toDate(24 * 60 * 60 - 60)))
val adapter = context?.let { context -> ArrayAdapter(context, R.layout.spinner_centered, timeList) }
overview_editquickwizard_from_spinner.adapter = adapter
overview_editquickwizard_to_spinner.adapter = adapter
overview_editquickwizard_button_edit.setText(entry.buttonText())
overview_editquickwizard_carbs_edit.setText(entry.carbs().toString())
overview_editquickwizard_from_spinner.setSelection(posFrom)
overview_editquickwizard_to_spinner.setSelection(posTo)
overview_editquickwizard_usebg_spinner.setSelection(entry.useBG())
overview_editquickwizard_usecob_spinner.setSelection(entry.useCOB())
overview_editquickwizard_usebolusiob_spinner.setSelection(entry.useBolusIOB())
overview_editquickwizard_usebasaliob_spinner.setSelection(entry.useBasalIOB())
overview_editquickwizard_usetrend_spinner.setSelection(entry.useTrend())
overview_editquickwizard_usesuperbolus_spinner.setSelection(entry.useSuperBolus())
overview_editquickwizard_usetemptarget_spinner.setSelection(entry.useTempTarget())
overview_editquickwizard_usecob_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) = processCob()
override fun onNothingSelected(parent: AdapterView<*>) {}
binding.from.setOnClickListener {
context?.let {
TimePickerDialog(it, fromTimeSetListener,
T.secs(fromSeconds.toLong()).hours().toInt(),
T.secs((fromSeconds % 3600).toLong()).mins().toInt(),
DateFormat.is24HourFormat(context)
).show()
}
}
fromSeconds = entry.validFrom()
binding.from.text = dateUtil.timeString(DateUtil.toDate(fromSeconds))
val toTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
toSeconds = (T.hours(hour.toLong()).secs() + T.mins(minute.toLong()).secs()).toInt()
binding.from.text = dateUtil.timeString(DateUtil.toDate(toSeconds))
}
binding.to.setOnClickListener {
context?.let {
TimePickerDialog(it, toTimeSetListener,
T.secs(fromSeconds.toLong()).hours().toInt(),
T.secs((fromSeconds % 3600).toLong()).mins().toInt(),
DateFormat.is24HourFormat(context)
).show()
}
}
toSeconds = entry.validFrom()
binding.to.text = dateUtil.timeString(DateUtil.toDate(toSeconds))
binding.buttonEdit.setText(entry.buttonText())
binding.carbsEdit.setText(entry.carbs().toString())
binding.useBg.setSelection(entry.useBG())
binding.useCob.setSelection(entry.useCOB())
binding.useBolusIob.setSelection(entry.useBolusIOB())
binding.useBasalIob.setSelection(entry.useBasalIOB())
binding.useTrend.setSelection(entry.useTrend())
binding.useSuperBolus.setSelection(entry.useSuperBolus())
binding.useTempTarget.setSelection(entry.useTempTarget())
binding.useCobYes.setOnClickListener(this)
binding.useCobNo.setOnClickListener(this)
processCob()
}
override fun onClick(v: View?) {
processCob()
}
@ -120,15 +145,20 @@ class EditQuickWizardDialog : DaggerDialogFragment() {
outState.putInt("position", position)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun processCob() {
if (overview_editquickwizard_usecob_spinner.selectedItemPosition == QuickWizardEntry.YES) {
overview_editquickwizard_usebolusiob_spinner.isEnabled = false
overview_editquickwizard_usebasaliob_spinner.isEnabled = false
overview_editquickwizard_usebolusiob_spinner.setSelection(QuickWizardEntry.YES)
overview_editquickwizard_usebasaliob_spinner.setSelection(QuickWizardEntry.YES)
if (binding.useCob.selectedItemPosition == QuickWizardEntry.YES) {
binding.useBolusIob.setEnableForChildren(false)
binding.useBasalIob.setEnableForChildren(false)
binding.useBolusIob.setSelection(QuickWizardEntry.YES)
binding.useBasalIob.setSelection(QuickWizardEntry.YES)
} else {
overview_editquickwizard_usebolusiob_spinner.isEnabled = true
overview_editquickwizard_usebasaliob_spinner.isEnabled = true
binding.useBolusIob.setEnableForChildren(true)
binding.useBasalIob.setEnableForChildren(true)
}
}
}

View file

@ -12,9 +12,10 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.GlucoseValueDataPoint
import info.nightscout.androidaps.data.IobTotal
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.LoopInterface
import info.nightscout.androidaps.interfaces.ProfileFunction
@ -35,7 +36,7 @@ import kotlin.math.max
import kotlin.math.min
class GraphData(
injector: HasAndroidInjector,
private val injector: HasAndroidInjector,
private val graph: GraphView,
private val iobCobCalculatorPlugin: IobCobCalculatorPlugin,
private val treatmentsPlugin: TreatmentsInterface
@ -50,7 +51,7 @@ class GraphData(
var maxY = Double.MIN_VALUE
private var minY = Double.MAX_VALUE
private var bgReadingsArray: List<BgReading>? = null
private var bgReadingsArray: List<GlucoseValue>? = null
private val units: String
private val series: MutableList<Series<*>> = ArrayList()
@ -60,7 +61,7 @@ class GraphData(
}
@Suppress("UNUSED_PARAMETER")
fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList<BgReading>?) {
fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList<GlucoseValueDataPoint>?) {
var maxBgValue = Double.MIN_VALUE
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
if (bgReadingsArray?.isEmpty() != false) {
@ -71,13 +72,13 @@ class GraphData(
}
val bgListArray: MutableList<DataPointWithLabelInterface> = ArrayList()
for (bg in bgReadingsArray!!) {
if (bg.date < fromTime || bg.date > toTime) continue
if (bg.timestamp < fromTime || bg.timestamp > toTime) continue
if (bg.value > maxBgValue) maxBgValue = bg.value
bgListArray.add(bg)
bgListArray.add(GlucoseValueDataPoint(injector, bg))
}
if (predictions != null) {
predictions.sortWith(Comparator { o1: BgReading, o2: BgReading -> o1.x.compareTo(o2.x) })
for (prediction in predictions) if (prediction.value >= 40) bgListArray.add(prediction)
predictions.sortWith(Comparator { o1: GlucoseValueDataPoint, o2: GlucoseValueDataPoint -> o1.x.compareTo(o2.x) })
for (prediction in predictions) if (prediction.data.value >= 40) bgListArray.add(prediction)
}
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units)
maxBgValue = addUpperChartMargin(maxBgValue)
@ -212,8 +213,7 @@ class GraphData(
var time = fromTime
while (time < toTime) {
val tt = treatmentsPlugin.getTempTargetFromHistory(time)
var value: Double
value = if (tt == null) {
val value: Double = if (tt == null) {
Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
} else {
Profile.fromMgdlToUnits(tt.target(), units)
@ -282,7 +282,7 @@ class GraphData(
bgReadingsArray?.let { bgReadingsArray ->
for (r in bgReadingsArray.indices) {
val reading = bgReadingsArray[r]
if (reading.date > date) continue
if (reading.timestamp > date) continue
return Profile.fromMgdlToUnits(reading.value, units)
}
return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, units) else Profile.fromMgdlToUnits(100.0, units)
@ -329,8 +329,51 @@ class GraphData(
actScale.setMultiplier(maxY * scale / maxIAValue)
}
//Function below show -BGI to be able to compare curves with deviations
fun addMinusBGI(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
val bgiArrayHist: MutableList<ScaledDataPoint> = ArrayList()
val bgiArrayPred: MutableList<ScaledDataPoint> = ArrayList()
val now = System.currentTimeMillis().toDouble()
val bgiScale = Scale()
var total: IobTotal
var maxBGIValue = 0.0
var time = fromTime
while (time <= toTime) {
val profile = profileFunction.getProfile(time)
if (profile == null) {
time += 5 * 60 * 1000L
continue
}
val deviation = if (devBgiScale) iobCobCalculatorPlugin.getAutosensData(time)?.deviation ?:0.0 else 0.0
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
val bgi: Double = total.activity * profile.getIsfMgdl(time) * 5.0
if (time <= now) bgiArrayHist.add(ScaledDataPoint(time, bgi, bgiScale)) else bgiArrayPred.add(ScaledDataPoint(time, bgi, bgiScale))
maxBGIValue = max(maxBGIValue, max(abs(bgi), deviation))
time += 5 * 60 * 1000L
}
addSeries(FixedLineGraphSeries(Array(bgiArrayHist.size) { i -> bgiArrayHist[i] }).also {
it.isDrawBackground = false
it.color = resourceHelper.gc(R.color.bgi)
it.thickness = 3
})
addSeries(FixedLineGraphSeries(Array(bgiArrayPred.size) { i -> bgiArrayPred[i] }).also {
it.setCustomPaint(Paint().also { paint ->
paint.style = Paint.Style.STROKE
paint.strokeWidth = 3f
paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
paint.color = resourceHelper.gc(R.color.bgi)
})
})
if (useForScale) {
maxY = maxBGIValue
minY = -maxBGIValue
}
bgiScale.setMultiplier(maxY * scale / maxBGIValue)
}
// scale in % of vertical size (like 0.3)
fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean) {
fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean, absScale: Boolean) {
val iobSeries: FixedLineGraphSeries<ScaledDataPoint?>
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
var maxIobValueFound = Double.MIN_VALUE
@ -340,11 +383,15 @@ class GraphData(
while (time <= toTime) {
val profile = profileFunction.getProfile(time)
var iob = 0.0
if (profile != null) iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
var absIob = 0.0
if (profile != null) {
iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
if (absScale) absIob = iobCobCalculatorPlugin.calculateAbsInsulinFromTreatmentsAndTempsSynchronized(time, profile).iob
}
if (abs(lastIob - iob) > 0.02) {
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
iobArray.add(ScaledDataPoint(time, iob, iobScale))
maxIobValueFound = max(maxIobValueFound, abs(iob))
maxIobValueFound = if (absScale) max(maxIobValueFound, abs(absIob)) else max(maxIobValueFound, abs(iob))
lastIob = iob
}
time += 5 * 60 * 1000L
@ -460,14 +507,23 @@ class GraphData(
}
// scale in % of vertical size (like 0.3)
fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, devBgiScale: Boolean) {
class DeviationDataPoint(x: Double, y: Double, var color: Int, scale: Scale) : ScaledDataPoint(x, y, scale)
val devArray: MutableList<DeviationDataPoint> = ArrayList()
var maxDevValueFound = 0.0
val devScale = Scale()
var time = fromTime
var total: IobTotal
while (time <= toTime) {
// if align Dev Scale with BGI scale, then calculate BGI value, else bgi = 0.0
val bgi: Double = if (devBgiScale) {
val profile = profileFunction.getProfile(time)
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
total.activity * (profile?.getIsfMgdl(time) ?: 0.0) * 5.0
} else 0.0
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
var color = resourceHelper.gc(R.color.deviationblack) // "="
if (autosensData.type == "" || autosensData.type == "non-meal") {
@ -480,7 +536,7 @@ class GraphData(
color = resourceHelper.gc(R.color.deviationgrey)
}
devArray.add(DeviationDataPoint(time.toDouble(), autosensData.deviation, color, devScale))
maxDevValueFound = max(maxDevValueFound, abs(autosensData.deviation))
maxDevValueFound = max(maxDevValueFound, max(abs(autosensData.deviation), abs(bgi)))
}
time += 5 * 60 * 1000L
}

View file

@ -9,7 +9,9 @@ import javax.inject.Inject
class DismissNotificationService : DaggerIntentService(DismissNotificationService::class.simpleName) {
@Inject lateinit var rxBus: RxBusWrapper
override fun onHandleIntent(intent: Intent) {
rxBus.send(EventDismissNotification(intent.getIntExtra("alertID", -1)))
override fun onHandleIntent(intent: Intent?) {
intent?.let {
rxBus.send(EventDismissNotification(intent.getIntExtra("alertID", -1)))
}
}
}

View file

@ -12,8 +12,8 @@ import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.androidNotification.NotificationHolder
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
/**
@ -21,6 +21,7 @@ import javax.inject.Inject
*/
class DummyService : DaggerService() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var fabricPrivacy: FabricPrivacy
@ -47,7 +48,7 @@ class DummyService : DaggerService() {
}
disposable.add(rxBus
.toObservable(EventAppExit::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({
aapsLogger.debug(LTag.CORE, "EventAppExit received")
stopSelf()

View file

@ -7,10 +7,8 @@ import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.core.app.RemoteInput
import androidx.core.app.TaskStackBuilder
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.events.*
@ -26,8 +24,9 @@ import info.nightscout.androidaps.utils.androidNotification.NotificationHolder
import info.nightscout.androidaps.utils.androidNotification.openAppIntent
import info.nightscout.androidaps.utils.resources.IconsProvider
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.valueToUnitsString
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
import javax.inject.Singleton
@ -37,6 +36,7 @@ class PersistentNotificationPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
private val aapsSchedulers: AapsSchedulers,
private val profileFunction: ProfileFunction,
private val fabricPrivacy: FabricPrivacy,
private val activePlugins: ActivePluginProvider,
@ -74,36 +74,36 @@ class PersistentNotificationPlugin @Inject constructor(
createNotificationChannel() // make sure channels exist before triggering updates through the bus
disposable.add(rxBus
.toObservable(EventRefreshOverview::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventExtendedBolusChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTempBasalChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTreatmentChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventInitializationChanged::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventNewBasalProfile::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ triggerNotificationUpdate() }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ triggerNotificationUpdate() }, fabricPrivacy::logException))
triggerNotificationUpdate()
}
@ -136,12 +136,12 @@ class PersistentNotificationPlugin @Inject constructor(
val lastBG = iobCobCalculatorPlugin.lastBg()
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (lastBG != null) {
line1aa = lastBG.valueToUnitsToString(units)
line1aa = lastBG.valueToUnitsString(units)
line1 = line1aa
if (glucoseStatus != null) {
line1 += (" Δ" + Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)
+ " avgΔ" + Profile.toSignedUnitsString(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units))
line1aa += " " + lastBG.directionToSymbol(databaseHelper)
line1aa += " " + lastBG.trendArrow.symbol
} else {
line1 += " " +
resourceHelper.gs(R.string.old_data) +

View file

@ -21,7 +21,7 @@ class AuthRequest internal constructor(
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var otp : OneTimePassword
@Inject lateinit var otp: OneTimePassword
private val date = DateUtil.now()
private var processed = false
@ -31,13 +31,8 @@ class AuthRequest internal constructor(
smsCommunicatorPlugin.sendSMS(Sms(requester.phoneNumber, requestText))
}
private fun codeIsValid(toValidate: String) : Boolean {
return if (otp.isEnabled()) {
otp.checkOTP(toValidate) == OneTimePasswordValidationResult.OK
} else {
confirmCode == toValidate
}
}
private fun codeIsValid(toValidate: String): Boolean =
otp.checkOTP(toValidate) == OneTimePasswordValidationResult.OK
fun action(codeReceived: String) {
if (processed) {

View file

@ -5,31 +5,40 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.SmscommunicatorFragmentBinding
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.smsCommunicator.events.EventSmsCommunicatorUpdateGui
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.extensions.plusAssign
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.smscommunicator_fragment.*
import java.util.*
import javax.inject.Inject
import kotlin.math.max
class SmsCommunicatorFragment : DaggerFragment() {
@Inject lateinit var fabricPrivacy : FabricPrivacy
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var dateUtil: DateUtil
private val disposable = CompositeDisposable()
private var _binding: SmscommunicatorFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.smscommunicator_fragment, container, false)
savedInstanceState: Bundle?): View {
_binding = SmscommunicatorFragmentBinding.inflate(inflater, container, false)
return binding.root
}
@Synchronized
@ -37,8 +46,8 @@ class SmsCommunicatorFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventSmsCommunicatorUpdateGui::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGui() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.main)
.subscribe({ updateGui() }, fabricPrivacy::logException)
updateGui()
}
@ -48,8 +57,15 @@ class SmsCommunicatorFragment : DaggerFragment() {
disposable.clear()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
fun updateGui() {
if (_binding == null) return
class CustomComparator : Comparator<Sms> {
override fun compare(object1: Sms, object2: Sms): Int {
return (object1.date - object2.date).toInt()
}
@ -74,6 +90,6 @@ class SmsCommunicatorFragment : DaggerFragment() {
}
}
}
smscommunicator_log?.text = HtmlHelper.fromHtml(logText)
binding.log.text = HtmlHelper.fromHtml(logText)
}
}

View file

@ -1,12 +1,14 @@
package info.nightscout.androidaps.plugins.general.smsCommunicator
import android.content.Intent
import android.content.Context
import android.telephony.SmsManager
import android.telephony.SmsMessage
import android.text.TextUtils
import androidx.preference.EditTextPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.work.Worker
import androidx.work.WorkerParameters
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.Config
import info.nightscout.androidaps.Constants
@ -32,24 +34,29 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.receivers.BundleStore
import info.nightscout.androidaps.receivers.DataReceiver
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import org.apache.commons.lang3.StringUtils
import java.text.Normalizer
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.max
import kotlin.math.min
@Singleton
class SmsCommunicatorPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
private val aapsSchedulers: AapsSchedulers,
private val sp: SP,
private val constraintChecker: ConstraintChecker,
private val rxBus: RxBusWrapper,
@ -102,8 +109,8 @@ class SmsCommunicatorPlugin @Inject constructor(
super.onStart()
disposable += rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ event: EventPreferenceChange? -> processSettings(event) }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventPreferenceChange? -> processSettings(event) }, fabricPrivacy::logException)
}
override fun onStop() {
@ -144,13 +151,38 @@ class SmsCommunicatorPlugin @Inject constructor(
override fun updatePreferenceSummary(pref: Preference) {
super.updatePreferenceSummary(pref)
if (pref is EditTextPreference) {
val editTextPref = pref
if (pref.getKey().contains("smscommunicator_allowednumbers") && (editTextPref.text == null || TextUtils.isEmpty(editTextPref.text.trim { it <= ' ' }))) {
if (pref.getKey().contains("smscommunicator_allowednumbers") && (pref.text == null || TextUtils.isEmpty(pref.text.trim { it <= ' ' }))) {
pref.setSummary(resourceHelper.gs(R.string.smscommunicator_allowednumbers_summary))
}
}
}
// cannot be inner class because of needed injection
class SmsCommunicatorWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var bundleStore: BundleStore
init {
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
}
override fun doWork(): Result {
val bundle = bundleStore.pickup(inputData.getLong(DataReceiver.STORE_KEY, -1))
?: return Result.failure()
val format = bundle.getString("format") ?: return Result.failure()
val pdus = bundle["pdus"] as Array<*>
for (pdu in pdus) {
val message = SmsMessage.createFromPdu(pdu as ByteArray, format)
smsCommunicatorPlugin.processSms(Sms(message))
}
return Result.success()
}
}
private fun processSettings(ev: EventPreferenceChange?) {
if (ev == null || ev.isChanged(resourceHelper, R.string.key_smscommunicator_allowednumbers)) {
val settings = sp.getString(R.string.key_smscommunicator_allowednumbers, "")
@ -179,16 +211,6 @@ class SmsCommunicatorPlugin @Inject constructor(
return false
}
fun handleNewData(intent: Intent) {
val bundle = intent.extras ?: return
val format = bundle.getString("format") ?: return
val pdus = bundle["pdus"] as Array<*>
for (pdu in pdus) {
val message = SmsMessage.createFromPdu(pdu as ByteArray, format)
processSms(Sms(message))
}
}
fun processSms(receivedSms: Sms) {
if (!isEnabled(PluginType.GENERAL)) {
aapsLogger.debug(LTag.SMS, "Ignoring SMS. Plugin disabled.")
@ -204,7 +226,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val pump = activePlugin.activePump
messages.add(receivedSms)
aapsLogger.debug(LTag.SMS, receivedSms.toString())
val splitted = receivedSms.text.split(Regex("\\s+")).toTypedArray()
val divided = receivedSms.text.split(Regex("\\s+")).toTypedArray()
val remoteCommandsAllowed = sp.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)
val minDistance =
@ -212,65 +234,65 @@ class SmsCommunicatorPlugin @Inject constructor(
T.mins(sp.getLong(R.string.key_smscommunicator_remotebolusmindistance, T.msecs(Constants.remoteBolusMinDistance).mins())).msecs()
else Constants.remoteBolusMinDistance
if (splitted.isNotEmpty() && isCommand(splitted[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
when (splitted[0].toUpperCase(Locale.getDefault())) {
"BG" ->
if (splitted.size == 1) processBG(receivedSms)
if (divided.isNotEmpty() && isCommand(divided[0].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
when (divided[0].toUpperCase(Locale.getDefault())) {
"BG" ->
if (divided.size == 1) processBG(receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"LOOP" ->
"LOOP" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2 || splitted.size == 3) processLOOP(splitted, receivedSms)
else if (divided.size == 2 || divided.size == 3) processLOOP(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"TREATMENTS" ->
if (splitted.size == 2) processTREATMENTS(splitted, receivedSms)
if (divided.size == 2) processTREATMENTS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"NSCLIENT" ->
if (splitted.size == 2) processNSCLIENT(splitted, receivedSms)
"NSCLIENT" ->
if (divided.size == 2) processNSCLIENT(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"PUMP" ->
if (!remoteCommandsAllowed && splitted.size > 1) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size <= 3) processPUMP(splitted, receivedSms)
"PUMP" ->
if (!remoteCommandsAllowed && divided.size > 1) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (divided.size <= 3) processPUMP(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"PROFILE" ->
"PROFILE" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2 || splitted.size == 3) processPROFILE(splitted, receivedSms)
else if (divided.size == 2 || divided.size == 3) processPROFILE(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"BASAL" ->
"BASAL" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2 || splitted.size == 3) processBASAL(splitted, receivedSms)
else if (divided.size == 2 || divided.size == 3) processBASAL(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"EXTENDED" ->
"EXTENDED" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2 || splitted.size == 3) processEXTENDED(splitted, receivedSms)
else if (divided.size == 2 || divided.size == 3) processEXTENDED(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"BOLUS" ->
"BOLUS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2 && DateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed)))
else if (splitted.size == 2 && pump.isSuspended) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
else if (splitted.size == 2 || splitted.size == 3) processBOLUS(splitted, receivedSms)
else if (divided.size == 2 && DateUtil.now() - lastRemoteBolusTime < minDistance) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotebolusnotallowed)))
else if (divided.size == 2 && pump.isSuspended) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.pumpsuspended)))
else if (divided.size == 2 || divided.size == 3) processBOLUS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"CARBS" ->
"CARBS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2 || splitted.size == 3) processCARBS(splitted, receivedSms)
else if (divided.size == 2 || divided.size == 3) processCARBS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"CAL" ->
"CAL" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2) processCAL(splitted, receivedSms)
else if (divided.size == 2) processCAL(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"TARGET" ->
"TARGET" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2) processTARGET(splitted, receivedSms)
else if (divided.size == 2) processTARGET(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"SMS" ->
"SMS" ->
if (!remoteCommandsAllowed) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_remotecommandnotallowed)))
else if (splitted.size == 2) processSMS(splitted, receivedSms)
else if (divided.size == 2) processSMS(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
"HELP" ->
if (splitted.size == 1 || splitted.size == 2) processHELP(splitted, receivedSms)
"HELP" ->
if (divided.size == 1 || divided.size == 2) processHELP(divided, receivedSms)
else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else ->
if (messageToConfirm?.requester?.phoneNumber == receivedSms.phoneNumber) {
messageToConfirm?.action(splitted[0])
messageToConfirm?.action(divided[0])
messageToConfirm = null
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_unknowncommand)))
}
@ -284,11 +306,11 @@ class SmsCommunicatorPlugin @Inject constructor(
var reply = ""
val units = profileFunction.getUnits()
if (actualBG != null) {
reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsToString(units) + ", "
reply = resourceHelper.gs(R.string.sms_actualbg) + " " + actualBG.valueToUnitsString(units) + ", "
} else if (lastBG != null) {
val agoMsec = System.currentTimeMillis() - lastBG.date
val agoMsec = System.currentTimeMillis() - lastBG.timestamp
val agoMin = (agoMsec / 60.0 / 1000.0).toInt()
reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsToString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", "
reply = resourceHelper.gs(R.string.sms_lastbg) + " " + lastBG.valueToUnitsString(units) + " " + String.format(resourceHelper.gs(R.string.sms_minago), agoMin) + ", "
}
val glucoseStatus = GlucoseStatus(injector).glucoseStatusData
if (glucoseStatus != null) reply += resourceHelper.gs(R.string.sms_delta) + " " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units + ", "
@ -305,11 +327,11 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
}
private fun processLOOP(splitted: Array<String>, receivedSms: Sms) {
when (splitted[1].toUpperCase(Locale.getDefault())) {
private fun processLOOP(divided: Array<String>, receivedSms: Sms) {
when (divided[1].toUpperCase(Locale.getDefault())) {
"DISABLE", "STOP" -> {
if (loopPlugin.isEnabled(PluginType.LOOP)) {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopdisablereplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -333,7 +355,7 @@ class SmsCommunicatorPlugin @Inject constructor(
"ENABLE", "START" -> {
if (!loopPlugin.isEnabled(PluginType.LOOP)) {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopenablereplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -349,7 +371,7 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
}
"STATUS" -> {
"STATUS" -> {
val reply = if (loopPlugin.isEnabled(PluginType.LOOP)) {
if (loopPlugin.isSuspended) String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())
else resourceHelper.gs(R.string.smscommunicator_loopisenabled)
@ -359,8 +381,8 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
}
"RESUME" -> {
val passCode = generatePasscode()
"RESUME" -> {
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_loopresumereplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -383,17 +405,17 @@ class SmsCommunicatorPlugin @Inject constructor(
})
}
"SUSPEND" -> {
"SUSPEND" -> {
var duration = 0
if (splitted.size == 3) duration = SafeParse.stringToInt(splitted[2])
duration = Math.max(0, duration)
duration = Math.min(180, duration)
if (divided.size == 3) duration = SafeParse.stringToInt(divided[2])
duration = max(0, duration)
duration = min(180, duration)
if (duration == 0) {
receivedSms.processed = true
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_wrongduration)))
return
} else {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_suspendreplywithcode), duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(duration) {
@ -424,8 +446,8 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
private fun processTREATMENTS(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "REFRESH") {
private fun processTREATMENTS(divided: Array<String>, receivedSms: Sms) {
if (divided[1].toUpperCase(Locale.getDefault()) == "REFRESH") {
(activePlugin.activeTreatments as TreatmentsPlugin).service.resetTreatments()
rxBus.send(EventNSClientRestart())
sendSMS(Sms(receivedSms.phoneNumber, "TREATMENTS REFRESH SENT"))
@ -434,8 +456,8 @@ class SmsCommunicatorPlugin @Inject constructor(
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
}
private fun processNSCLIENT(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "RESTART") {
private fun processNSCLIENT(divided: Array<String>, receivedSms: Sms) {
if (divided[1].toUpperCase(Locale.getDefault()) == "RESTART") {
rxBus.send(EventNSClientRestart())
sendSMS(Sms(receivedSms.phoneNumber, "NSCLIENT RESTART SENT"))
receivedSms.processed = true
@ -443,21 +465,26 @@ class SmsCommunicatorPlugin @Inject constructor(
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
}
private fun processHELP(splitted: Array<String>, receivedSms: Sms) {
if (splitted.size == 1) {
sendSMS(Sms(receivedSms.phoneNumber, commands.keys.toString().replace("[", "").replace("]", "")))
receivedSms.processed = true
} else if (isCommand(splitted[1].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber)) {
commands[splitted[1].toUpperCase(Locale.getDefault())]?.let {
sendSMS(Sms(receivedSms.phoneNumber, it))
private fun processHELP(divided: Array<String>, receivedSms: Sms) {
when {
divided.size == 1 -> {
sendSMS(Sms(receivedSms.phoneNumber, commands.keys.toString().replace("[", "").replace("]", "")))
receivedSms.processed = true
}
} else
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
isCommand(divided[1].toUpperCase(Locale.getDefault()), receivedSms.phoneNumber) -> {
commands[divided[1].toUpperCase(Locale.getDefault())]?.let {
sendSMS(Sms(receivedSms.phoneNumber, it))
receivedSms.processed = true
}
}
else -> sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
}
}
private fun processPUMP(splitted: Array<String>, receivedSms: Sms) {
if (splitted.size == 1) {
private fun processPUMP(divided: Array<String>, receivedSms: Sms) {
if (divided.size == 1) {
commandQueue.readStatus("SMS", object : Callback() {
override fun run() {
val pump = activePlugin.activePump
@ -471,8 +498,8 @@ class SmsCommunicatorPlugin @Inject constructor(
}
})
receivedSms.processed = true
} else if ((splitted.size == 2) && (splitted[1].equals("CONNECT", ignoreCase = true))) {
val passCode = generatePasscode()
} else if ((divided.size == 2) && (divided[1].equals("CONNECT", ignoreCase = true))) {
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_pumpconnectwithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -492,16 +519,16 @@ class SmsCommunicatorPlugin @Inject constructor(
})
}
})
} else if ((splitted.size == 3) && (splitted[1].equals("DISCONNECT", ignoreCase = true))) {
var duration = SafeParse.stringToInt(splitted[2])
duration = Math.max(0, duration)
duration = Math.min(120, duration)
} else if ((divided.size == 3) && (divided[1].equals("DISCONNECT", ignoreCase = true))) {
var duration = SafeParse.stringToInt(divided[2])
duration = max(0, duration)
duration = min(120, duration)
if (duration == 0) {
receivedSms.processed = true
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.smscommunicator_wrongduration)))
return
} else {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_pumpdisconnectwithcode), duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -520,7 +547,7 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
private fun processPROFILE(splitted: Array<String>, receivedSms: Sms) { // load profiles
private fun processPROFILE(divided: Array<String>, receivedSms: Sms) { // load profiles
val anInterface = activePlugin.activeProfileInterface
val store = anInterface.profile
if (store == null) {
@ -530,9 +557,9 @@ class SmsCommunicatorPlugin @Inject constructor(
}
val profileName = profileFunction.getProfileName()
val list = store.getProfileList()
if (splitted[1].toUpperCase(Locale.getDefault()) == "STATUS") {
if (divided[1].toUpperCase(Locale.getDefault()) == "STATUS") {
sendSMS(Sms(receivedSms.phoneNumber, profileName))
} else if (splitted[1].toUpperCase(Locale.getDefault()) == "LIST") {
} else if (divided[1].toUpperCase(Locale.getDefault()) == "LIST") {
if (list.isEmpty()) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.invalidprofile)))
else {
var reply = ""
@ -544,9 +571,9 @@ class SmsCommunicatorPlugin @Inject constructor(
sendSMS(Sms(receivedSms.phoneNumber, reply))
}
} else {
val pindex = SafeParse.stringToInt(splitted[1])
val pindex = SafeParse.stringToInt(divided[1])
var percentage = 100
if (splitted.size > 2) percentage = SafeParse.stringToInt(splitted[2])
if (divided.size > 2) percentage = SafeParse.stringToInt(divided[2])
if (pindex > list.size) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (percentage == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (pindex == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
@ -554,7 +581,7 @@ class SmsCommunicatorPlugin @Inject constructor(
val profile = store.getSpecificProfile(list[pindex - 1] as String)
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile)))
else {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_profilereplywithcode), list[pindex - 1], percentage, passCode)
receivedSms.processed = true
val finalPercentage = percentage
@ -571,9 +598,9 @@ class SmsCommunicatorPlugin @Inject constructor(
receivedSms.processed = true
}
private fun processBASAL(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "CANCEL" || splitted[1].toUpperCase(Locale.getDefault()) == "STOP") {
val passCode = generatePasscode()
private fun processBASAL(divided: Array<String>, receivedSms: Sms) {
if (divided[1].toUpperCase(Locale.getDefault()) == "CANCEL" || divided[1].toUpperCase(Locale.getDefault()) == "STOP") {
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalstopreplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -594,18 +621,18 @@ class SmsCommunicatorPlugin @Inject constructor(
})
}
})
} else if (splitted[1].endsWith("%")) {
var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(splitted[1], "%"))
} else if (divided[1].endsWith("%")) {
var tempBasalPct = SafeParse.stringToInt(StringUtils.removeEnd(divided[1], "%"))
val durationStep = activePlugin.activePump.model().tbrSettings.durationStep
var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
if (divided.size > 2) duration = SafeParse.stringToInt(divided[2])
val profile = profileFunction.getProfile()
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile)))
else if (tempBasalPct == 0 && splitted[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (tempBasalPct == 0 && divided[1] != "0%") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongTbrDuration, durationStep)))
else {
tempBasalPct = constraintChecker.applyBasalPercentConstraints(Constraint(tempBasalPct), profile).value()
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalpctreplywithcode), tempBasalPct, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasalPct, duration) {
@ -614,8 +641,7 @@ class SmsCommunicatorPlugin @Inject constructor(
commandQueue.tempBasalPercent(anInteger(), secondInteger(), true, profile, object : Callback() {
override fun run() {
if (result.success) {
var replyText: String
replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
var replyText = if (result.isPercent) String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset_percent), result.percent, result.duration) else String.format(resourceHelper.gs(R.string.smscommunicator_tempbasalset), result.absolute, result.duration)
replyText += "\n" + activePlugin.activePump.shortStatus(true)
sendSMSToAllNumbers(Sms(receivedSms.phoneNumber, replyText))
} else {
@ -629,17 +655,17 @@ class SmsCommunicatorPlugin @Inject constructor(
})
}
} else {
var tempBasal = SafeParse.stringToDouble(splitted[1])
var tempBasal = SafeParse.stringToDouble(divided[1])
val durationStep = activePlugin.activePump.model().tbrSettings.durationStep
var duration = 30
if (splitted.size > 2) duration = SafeParse.stringToInt(splitted[2])
if (divided.size > 2) duration = SafeParse.stringToInt(divided[2])
val profile = profileFunction.getProfile()
if (profile == null) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.noprofile)))
else if (tempBasal == 0.0 && splitted[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (tempBasal == 0.0 && divided[1] != "0") sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else if (duration <= 0 || duration % durationStep != 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongTbrDuration, durationStep)))
else {
tempBasal = constraintChecker.applyBasalConstraints(Constraint(tempBasal), profile).value()
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_basalreplywithcode), tempBasal, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(tempBasal, duration) {
@ -665,9 +691,9 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
private fun processEXTENDED(splitted: Array<String>, receivedSms: Sms) {
if (splitted[1].toUpperCase(Locale.getDefault()) == "CANCEL" || splitted[1].toUpperCase(Locale.getDefault()) == "STOP") {
val passCode = generatePasscode()
private fun processEXTENDED(divided: Array<String>, receivedSms: Sms) {
if (divided[1].toUpperCase(Locale.getDefault()) == "CANCEL" || divided[1].toUpperCase(Locale.getDefault()) == "STOP") {
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedstopreplywithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -688,15 +714,15 @@ class SmsCommunicatorPlugin @Inject constructor(
})
}
})
} else if (splitted.size != 3) {
} else if (divided.size != 3) {
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
} else {
var extended = SafeParse.stringToDouble(splitted[1])
val duration = SafeParse.stringToInt(splitted[2])
var extended = SafeParse.stringToDouble(divided[1])
val duration = SafeParse.stringToInt(divided[2])
extended = constraintChecker.applyExtendedBolusConstraints(Constraint(extended)).value()
if (extended == 0.0 || duration == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_extendedreplywithcode), extended, duration, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(extended, duration) {
@ -722,14 +748,14 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
private fun processBOLUS(splitted: Array<String>, receivedSms: Sms) {
var bolus = SafeParse.stringToDouble(splitted[1])
val isMeal = splitted.size > 2 && splitted[2].equals("MEAL", ignoreCase = true)
private fun processBOLUS(divided: Array<String>, receivedSms: Sms) {
var bolus = SafeParse.stringToDouble(divided[1])
val isMeal = divided.size > 2 && divided[2].equals("MEAL", ignoreCase = true)
bolus = constraintChecker.applyBolusConstraints(Constraint(bolus)).value()
if (splitted.size == 3 && !isMeal) {
if (divided.size == 3 && !isMeal) {
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
} else if (bolus > 0.0) {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = if (isMeal)
String.format(resourceHelper.gs(R.string.smscommunicator_mealbolusreplywithcode), bolus, passCode)
else
@ -762,9 +788,11 @@ class SmsCommunicatorPlugin @Inject constructor(
else Constants.defaultEatingSoonTTDuration
var eatingSoonTT = sp.getDouble(R.string.key_eatingsoon_target, if (currentProfile.units == Constants.MMOL) Constants.defaultEatingSoonTTmmol else Constants.defaultEatingSoonTTmgdl)
eatingSoonTT =
if (eatingSoonTT > 0) eatingSoonTT
else if (currentProfile.units == Constants.MMOL) Constants.defaultEatingSoonTTmmol
else Constants.defaultEatingSoonTTmgdl
when {
eatingSoonTT > 0 -> eatingSoonTT
currentProfile.units == Constants.MMOL -> Constants.defaultEatingSoonTTmmol
else -> Constants.defaultEatingSoonTTmgdl
}
val tempTarget = TempTarget()
.date(System.currentTimeMillis())
.duration(eatingSoonTTDuration)
@ -794,11 +822,11 @@ class SmsCommunicatorPlugin @Inject constructor(
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
}
private fun processCARBS(splitted: Array<String>, receivedSms: Sms) {
var grams = SafeParse.stringToInt(splitted[1])
private fun processCARBS(divided: Array<String>, receivedSms: Sms) {
var grams = SafeParse.stringToInt(divided[1])
var time = DateUtil.now()
if (splitted.size > 2) {
time = DateUtil.toTodayTime(splitted[2].toUpperCase(Locale.getDefault()))
if (divided.size > 2) {
time = DateUtil.toTodayTime(divided[2].toUpperCase(Locale.getDefault()))
if (time == 0L) {
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
return
@ -807,7 +835,7 @@ class SmsCommunicatorPlugin @Inject constructor(
grams = constraintChecker.applyCarbsConstraints(Constraint(grams)).value()
if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
else {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_carbsreplywithcode), grams, dateUtil.timeString(time), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(grams, time) {
@ -842,14 +870,14 @@ class SmsCommunicatorPlugin @Inject constructor(
}
}
private fun processTARGET(splitted: Array<String>, receivedSms: Sms) {
val isMeal = splitted[1].equals("MEAL", ignoreCase = true)
val isActivity = splitted[1].equals("ACTIVITY", ignoreCase = true)
val isHypo = splitted[1].equals("HYPO", ignoreCase = true)
val isStop = splitted[1].equals("STOP", ignoreCase = true) || splitted[1].equals("CANCEL", ignoreCase = true)
private fun processTARGET(divided: Array<String>, receivedSms: Sms) {
val isMeal = divided[1].equals("MEAL", ignoreCase = true)
val isActivity = divided[1].equals("ACTIVITY", ignoreCase = true)
val isHypo = divided[1].equals("HYPO", ignoreCase = true)
val isStop = divided[1].equals("STOP", ignoreCase = true) || divided[1].equals("CANCEL", ignoreCase = true)
if (isMeal || isActivity || isHypo) {
val passCode = generatePasscode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetwithcode), splitted[1].toUpperCase(Locale.getDefault()), passCode)
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetwithcode), divided[1].toUpperCase(Locale.getDefault()), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
override fun run() {
@ -904,7 +932,7 @@ class SmsCommunicatorPlugin @Inject constructor(
}
})
} else if (isStop) {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_temptargetcancel), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -925,11 +953,11 @@ class SmsCommunicatorPlugin @Inject constructor(
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
}
private fun processSMS(splitted: Array<String>, receivedSms: Sms) {
val isStop = (splitted[1].equals("STOP", ignoreCase = true)
|| splitted[1].equals("DISABLE", ignoreCase = true))
private fun processSMS(divided: Array<String>, receivedSms: Sms) {
val isStop = (divided[1].equals("STOP", ignoreCase = true)
|| divided[1].equals("DISABLE", ignoreCase = true))
if (isStop) {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_stopsmswithcode), passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction() {
@ -943,10 +971,10 @@ class SmsCommunicatorPlugin @Inject constructor(
} else sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
}
private fun processCAL(splitted: Array<String>, receivedSms: Sms) {
val cal = SafeParse.stringToDouble(splitted[1])
private fun processCAL(divided: Array<String>, receivedSms: Sms) {
val cal = SafeParse.stringToDouble(divided[1])
if (cal > 0.0) {
val passCode = generatePasscode()
val passCode = generatePassCode()
val reply = String.format(resourceHelper.gs(R.string.smscommunicator_calibrationreplywithcode), cal, passCode)
receivedSms.processed = true
messageToConfirm = AuthRequest(injector, receivedSms, reply, passCode, object : SmsAction(cal) {
@ -1006,22 +1034,8 @@ class SmsCommunicatorPlugin @Inject constructor(
return true
}
private fun generatePasscode(): String {
if (otp.isEnabled()) {
// this not realy generate password - rather info to use Authenticator TOTP instead
return resourceHelper.gs(R.string.smscommunicator_code_from_authenticator_for, otp.name())
}
val startChar1 = 'A'.toInt() // on iphone 1st char is uppercase :)
var passCode = Character.toString((startChar1 + Math.random() * ('z' - 'a' + 1)).toChar())
val startChar2: Int = if (Math.random() > 0.5) 'a'.toInt() else 'A'.toInt()
passCode += Character.toString((startChar2 + Math.random() * ('z' - 'a' + 1)).toChar())
val startChar3: Int = if (Math.random() > 0.5) 'a'.toInt() else 'A'.toInt()
passCode += Character.toString((startChar3 + Math.random() * ('z' - 'a' + 1)).toChar())
passCode = passCode.replace('l', 'k').replace('I', 'J')
return passCode
}
private fun generatePassCode(): String =
String.format(resourceHelper.gs(R.string.smscommunicator_code_from_authenticator_for), otp.name())
private fun stripAccents(str: String): String {
var s = str
@ -1030,8 +1044,8 @@ class SmsCommunicatorPlugin @Inject constructor(
return s
}
private fun areMoreNumbers(allowednumbers: String?): Boolean {
return allowednumbers?.let {
private fun areMoreNumbers(allowedNumbers: String?): Boolean {
return allowedNumbers?.let {
val knownNumbers = HashSet<String>()
val substrings = it.split(";").toTypedArray()
for (number in substrings) {

View file

@ -14,6 +14,7 @@ import com.google.common.primitives.Ints.min
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.databinding.ActivitySmscommunicatorOtpBinding
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
@ -21,7 +22,6 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePas
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import kotlinx.android.synthetic.main.activity_smscommunicator_otp.*
import net.glxn.qrgen.android.QRCode
import javax.inject.Inject
@ -32,23 +32,27 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
@Inject lateinit var otp: OneTimePassword
private lateinit var binding: ActivitySmscommunicatorOtpBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
setContentView(R.layout.activity_smscommunicator_otp)
smscommunicator_otp_verify_edit.addTextChangedListener(object : TextWatcher {
binding = ActivitySmscommunicatorOtpBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.otpVerifyEdit.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
val checkResult = otp.checkOTP(s.toString())
smscommunicator_otp_verify_label.text = when (checkResult) {
binding.otpVerifyLabel.text = when (checkResult) {
OneTimePasswordValidationResult.OK -> "OK"
OneTimePasswordValidationResult.ERROR_WRONG_LENGTH -> "INVALID SIZE!"
OneTimePasswordValidationResult.ERROR_WRONG_PIN -> "WRONG PIN"
OneTimePasswordValidationResult.ERROR_WRONG_OTP -> "WRONG OTP"
}
smscommunicator_otp_verify_label.setTextColor(when (checkResult) {
binding.otpVerifyLabel.setTextColor(when (checkResult) {
OneTimePasswordValidationResult.OK -> Color.GREEN
OneTimePasswordValidationResult.ERROR_WRONG_LENGTH -> Color.YELLOW
OneTimePasswordValidationResult.ERROR_WRONG_PIN -> Color.RED
@ -61,7 +65,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
actions_smscommunicator_otp_reset.setOnClickListener {
binding.otpReset.setOnClickListener {
OKDialog.showConfirmation(this,
resourceHelper.gs(R.string.smscommunicator_otp_reset_title),
resourceHelper.gs(R.string.smscommunicator_otp_reset_prompt),
@ -72,7 +76,7 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
})
}
smscommunicator_otp_provisioning.setOnLongClickListener {
binding.otpProvisioning.setOnLongClickListener {
OKDialog.showConfirmation(this,
resourceHelper.gs(R.string.smscommunicator_otp_export_title),
resourceHelper.gs(R.string.smscommunicator_otp_export_prompt),
@ -104,12 +108,12 @@ class SmsCommunicatorOtpActivity : NoSplashAppCompatActivity() {
if (provURI != null) {
val myBitmap = QRCode.from(provURI).withErrorCorrection(ErrorCorrectionLevel.H).withSize(dim, dim).bitmap()
smscommunicator_otp_provisioning.setImageBitmap(myBitmap)
smscommunicator_otp_provisioning.visibility = View.VISIBLE
binding.otpProvisioning.setImageBitmap(myBitmap)
binding.otpProvisioning.visibility = View.VISIBLE
} else {
smscommunicator_otp_provisioning.visibility = View.GONE
binding.otpProvisioning.visibility = View.GONE
}
smscommunicator_otp_verify_edit.text = smscommunicator_otp_verify_edit.text
binding.otpVerifyEdit.text = binding.otpVerifyEdit.text
}
}

View file

@ -26,24 +26,9 @@ class OneTimePassword @Inject constructor(
private val totp = HmacOneTimePasswordGenerator()
init {
instance = this
configure()
}
companion object {
private lateinit var instance: OneTimePassword
@JvmStatic
fun getInstance(): OneTimePassword = instance
}
/**
* If OTP Authenticator support is enabled by user
*/
fun isEnabled(): Boolean {
return sp.getBoolean(R.string.key_smscommunicator_otp_enabled, true)
}
/**
* Name of master device (target of OTP)
*/

View file

@ -7,6 +7,7 @@ import android.view.ViewGroup
import android.widget.ScrollView
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.TidepoolFragmentBinding
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.tidepool.comm.TidepoolUploader
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolDoUpload
@ -14,31 +15,39 @@ import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolR
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolUpdateGUI
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.tidepool_fragment.*
import javax.inject.Inject
class TidepoolFragment : DaggerFragment() {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var tidepoolPlugin: TidepoolPlugin
@Inject lateinit var tidepoolUploader: TidepoolUploader
@Inject lateinit var sp: SP
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var aapsSchedulers: AapsSchedulers
private var disposable: CompositeDisposable = CompositeDisposable()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.tidepool_fragment, container, false)
private var _binding: TidepoolFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = TidepoolFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
tidepool_login.setOnClickListener { tidepoolUploader.doLogin(false) }
tidepool_uploadnow.setOnClickListener { rxBus.send(EventTidepoolDoUpload()) }
tidepool_removeall.setOnClickListener { rxBus.send(EventTidepoolResetData()) }
tidepool_resertstart.setOnClickListener { sp.putLong(R.string.key_tidepool_last_end, 0) }
binding.login.setOnClickListener { tidepoolUploader.doLogin(false) }
binding.uploadnow.setOnClickListener { rxBus.send(EventTidepoolDoUpload()) }
binding.removeall.setOnClickListener { rxBus.send(EventTidepoolResetData()) }
binding.resertstart.setOnClickListener { sp.putLong(R.string.key_tidepool_last_end, 0) }
}
@Synchronized
@ -46,14 +55,15 @@ class TidepoolFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventTidepoolUpdateGUI::class.java)
.observeOn(AndroidSchedulers.mainThread())
.observeOn(aapsSchedulers.main)
.subscribe({
if (_binding == null) return@subscribe
tidepoolPlugin.updateLog()
tidepool_log?.text = tidepoolPlugin.textLog
tidepool_status?.text = tidepoolUploader.connectionStatus.name
tidepool_log?.text = tidepoolPlugin.textLog
tidepool_logscrollview?.fullScroll(ScrollView.FOCUS_DOWN)
}, { fabricPrivacy.logException(it) })
binding.log.text = tidepoolPlugin.textLog
binding.status.text = tidepoolUploader.connectionStatus.name
binding.log.text = tidepoolPlugin.textLog
binding.logscrollview.fullScroll(ScrollView.FOCUS_DOWN)
}, fabricPrivacy::logException)
}
@Synchronized
@ -61,4 +71,11 @@ class TidepoolFragment : DaggerFragment() {
super.onPause()
disposable.clear()
}
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -32,9 +32,9 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@ -44,6 +44,7 @@ class TidepoolPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
private val aapsSchedulers: AapsSchedulers,
private val rxBus: RxBusWrapper,
private val context: Context,
private val fabricPrivacy: FabricPrivacy,
@ -71,11 +72,11 @@ class TidepoolPlugin @Inject constructor(
super.onStart()
disposable += rxBus
.toObservable(EventTidepoolDoUpload::class.java)
.observeOn(Schedulers.io())
.subscribe({ doUpload() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ doUpload() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventTidepoolResetData::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({
if (tidepoolUploader.connectionStatus != CONNECTED) {
aapsLogger.debug(LTag.TIDEPOOL, "Not connected for delete Dataset")
@ -84,49 +85,39 @@ class TidepoolPlugin @Inject constructor(
sp.putLong(R.string.key_tidepool_last_end, 0)
tidepoolUploader.doLogin()
}
}, {
fabricPrivacy.logException(it)
})
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventTidepoolStatus::class.java)
.observeOn(Schedulers.io())
.subscribe({ event -> addToLog(event) }, {
fabricPrivacy.logException(it)
})
.observeOn(aapsSchedulers.io)
.subscribe({ event -> addToLog(event) }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNewBG::class.java)
.observeOn(Schedulers.io())
.filter { it.bgReading != null } // better would be optional in API level >24
.map { it.bgReading }
.observeOn(aapsSchedulers.io)
.filter { it.glucoseValue != null } // better would be optional in API level >24
.map { it.glucoseValue }
.subscribe({ bgReading ->
if (bgReading!!.date < uploadChunk.getLastEnd())
uploadChunk.setLastEnd(bgReading.date)
if (bgReading!!.timestamp < uploadChunk.getLastEnd())
uploadChunk.setLastEnd(bgReading.timestamp )
if (isEnabled(PluginType.GENERAL)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging)
&& (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected)
&& rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt()))
doUpload()
}, {
fabricPrivacy.logException(it)
})
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ event ->
if (event.isChanged(resourceHelper, R.string.key_tidepool_dev_servers)
|| event.isChanged(resourceHelper, R.string.key_tidepool_username)
|| event.isChanged(resourceHelper, R.string.key_tidepool_password)
)
tidepoolUploader.resetInstance()
}, {
fabricPrivacy.logException(it)
})
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNetworkChange::class.java)
.observeOn(Schedulers.io())
.subscribe({}, {
fabricPrivacy.logException(it)
}) // TODO start upload on wifi connect
.observeOn(aapsSchedulers.io)
.subscribe({}, fabricPrivacy::logException) // TODO start upload on wifi connect
}
@ -150,7 +141,7 @@ class TidepoolPlugin @Inject constructor(
private fun doUpload() =
when (tidepoolUploader.connectionStatus) {
DISCONNECTED -> tidepoolUploader.doLogin(true)
CONNECTED -> tidepoolUploader.doUpload()
CONNECTED -> tidepoolUploader.doUpload()
else -> {
}

View file

@ -1,15 +1,17 @@
package info.nightscout.androidaps.plugins.general.tidepool.comm
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Intervals
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.db.TemporaryBasal
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.general.tidepool.elements.*
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
import info.nightscout.androidaps.plugins.general.tidepool.utils.GsonInstance
@ -24,12 +26,14 @@ import kotlin.math.max
@Singleton
class UploadChunk @Inject constructor(
private val injector: HasAndroidInjector,
private val sp: SP,
private val rxBus: RxBusWrapper,
private val aapsLogger: AAPSLogger,
private val profileFunction: ProfileFunction,
private val treatmentsPlugin: TreatmentsPlugin,
private val activePlugin: ActivePluginProvider,
private val repository: AppRepository,
private val dateUtil: DateUtil
) {
@ -102,9 +106,10 @@ class UploadChunk @Inject constructor(
val start: Long = 0
val end = DateUtil.now()
val bgReadingList = MainApp.getDbHelper().getBgreadingsDataFromTime(start, end, true)
return if (bgReadingList.size > 0)
bgReadingList[0].date
val bgReadingList = repository.compatGetBgReadingsDataFromTime(start, end, true)
.blockingGet()
return if (bgReadingList.isNotEmpty())
bgReadingList[0].timestamp
else -1
}
@ -131,7 +136,8 @@ class UploadChunk @Inject constructor(
}
private fun getBgReadings(start: Long, end: Long): List<SensorGlucoseElement> {
val readings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, end, true)
val readings = repository.compatGetBgReadingsDataFromTime(start, end, true)
.blockingGet()
val selection = SensorGlucoseElement.fromBgReadings(readings)
if (selection.isNotEmpty())
rxBus.send(EventTidepoolStatus("${selection.size} CGMs selected for upload"))

View file

@ -1,14 +1,15 @@
package info.nightscout.androidaps.plugins.general.tidepool.elements
import com.google.gson.annotations.Expose
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.database.entities.GlucoseValue
import java.util.*
class SensorGlucoseElement(bgReading: BgReading)
: BaseElement(bgReading.date, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.date).toByteArray()).toString()) {
class SensorGlucoseElement(bgReading: GlucoseValue)
: BaseElement(bgReading.timestamp, UUID.nameUUIDFromBytes(("AAPS-cgm" + bgReading.timestamp).toByteArray()).toString()) {
@Expose
internal var units: String = "mg/dL"
@Expose
internal var value: Int = 0
@ -18,7 +19,8 @@ class SensorGlucoseElement(bgReading: BgReading)
}
companion object {
internal fun fromBgReadings(bgReadingList: List<BgReading>): List<SensorGlucoseElement> {
internal fun fromBgReadings(bgReadingList: List<GlucoseValue>): List<SensorGlucoseElement> {
val results = LinkedList<SensorGlucoseElement>()
for (bgReading in bgReadingList) {
results.add(SensorGlucoseElement(bgReading))

View file

@ -31,11 +31,7 @@ import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.plugins.treatments.CarbsGenerator
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import info.nightscout.androidaps.utils.wizard.BolusWizard

View file

@ -10,8 +10,8 @@ import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
@ -19,9 +19,9 @@ import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpda
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
import javax.inject.Singleton
@ -30,6 +30,7 @@ class WearPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
private val aapsSchedulers: AapsSchedulers,
private val sp: SP,
private val mainApp: MainApp,
private val fabricPrivacy: FabricPrivacy,
@ -52,57 +53,57 @@ class WearPlugin @Inject constructor(
super.onStart()
disposable.add(rxBus
.toObservable(EventOpenAPSUpdateGui::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventExtendedBolusChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTempBasalChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTreatmentChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventNewBasalProfile::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendDataToWatch(status = false, basals = true, bgValue = false) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = false, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = true) }) { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = true) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({
// possibly new high or low mark
resendDataToWatch()
// status may be formatted differently
sendDataToWatch(status = true, basals = false, bgValue = false)
}) { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventRefreshOverview::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({
if (WatchUpdaterService.shouldReportLoopStatus(loopPlugin.get().isEnabled(PluginType.LOOP)))
sendDataToWatch(status = true, basals = false, bgValue = false)
}) { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventBolusRequested::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventBolusRequested ->
val status = String.format(resourceHelper.gs(R.string.bolusrequested), event.amount)
val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
intent.putExtra("progresspercent", 0)
intent.putExtra("progressstatus", status)
mainApp.startService(intent)
}) { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventDismissBolusProgressIfRunning::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventDismissBolusProgressIfRunning ->
if (event.result == null) return@subscribe
val status: String = if (event.result!!.success) {
@ -114,10 +115,10 @@ class WearPlugin @Inject constructor(
intent.putExtra("progresspercent", 100)
intent.putExtra("progressstatus", status)
mainApp.startService(intent)
}) { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventOverviewBolusProgress::class.java)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventOverviewBolusProgress ->
if (!event.isSMB() || sp.getBoolean("wear_notifySMB", true)) {
val intent = Intent(mainApp, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
@ -125,7 +126,7 @@ class WearPlugin @Inject constructor(
intent.putExtra("progressstatus", event.status)
mainApp.startService(intent)
}
}) { fabricPrivacy.logException(it) })
}, fabricPrivacy::logException))
}
override fun onStop() {

View file

@ -31,32 +31,33 @@ import dagger.android.AndroidInjection;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.GlucoseValueDataPoint;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus;
import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.DefaultValueHelper;
import info.nightscout.androidaps.utils.GlucoseValueUtilsKt;
import info.nightscout.androidaps.utils.ToastUtils;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import kotlin.Suppress;
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
@Inject public HasAndroidInjector injector;
@ -72,6 +73,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
@Inject public IobCobCalculatorPlugin iobCobCalculatorPlugin;
@Inject public TreatmentsPlugin treatmentsPlugin;
@Inject public ActionStringHandler actionStringHandler;
@Inject public AppRepository repository;
@Inject ReceiverStatusStore receiverStatusStore;
@Inject Config config;
@ -275,7 +277,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
private void sendData() {
BgReading lastBG = iobCobCalculatorPlugin.lastBg();
GlucoseValue lastBG = iobCobCalculatorPlugin.lastBg();
// Log.d(TAG, logPrefix + "LastBg=" + lastBG);
if (lastBG != null) {
GlucoseStatus glucoseStatus = new GlucoseStatus(injector).getGlucoseStatusData();
@ -297,25 +299,25 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
}
private DataMap dataMapSingleBG(BgReading lastBG, GlucoseStatus glucoseStatus) {
private DataMap dataMapSingleBG(GlucoseValue lastBG, GlucoseStatus glucoseStatus) {
String units = profileFunction.getUnits();
double convert2MGDL = 1.0;
if (units.equals(Constants.MMOL))
convert2MGDL = Constants.MMOLL_TO_MGDL;
double lowLine = defaultValueHelper.determineLowLine()*convert2MGDL;
double highLine = defaultValueHelper.determineHighLine()*convert2MGDL;
double lowLine = defaultValueHelper.determineLowLine() * convert2MGDL;
double highLine = defaultValueHelper.determineHighLine() * convert2MGDL;
long sgvLevel = 0L;
if (lastBG.value > highLine) {
if (lastBG.getValue() > highLine) {
sgvLevel = 1;
} else if (lastBG.value < lowLine) {
} else if (lastBG.getValue() < lowLine) {
sgvLevel = -1;
}
DataMap dataMap = new DataMap();
dataMap.putString("sgvString", lastBG.valueToUnitsToString(units));
dataMap.putString("sgvString", GlucoseValueUtilsKt.valueToUnitsString(lastBG, units));
dataMap.putString("glucoseUnits", units);
dataMap.putLong("timestamp", lastBG.date);
dataMap.putLong("timestamp", lastBG.getTimestamp());
if (glucoseStatus == null) {
dataMap.putString("slopeArrow", "");
dataMap.putString("delta", "--");
@ -326,7 +328,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
dataMap.putString("avgDelta", deltastring(glucoseStatus.avgdelta, glucoseStatus.avgdelta * Constants.MGDL_TO_MMOLL, units));
}
dataMap.putLong("sgvLevel", sgvLevel);
dataMap.putDouble("sgvDouble", lastBG.value);
dataMap.putDouble("sgvDouble", lastBG.getValue());
dataMap.putDouble("high", highLine);
dataMap.putDouble("low", lowLine);
return dataMap;
@ -381,11 +383,11 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
googleApiConnect();
}
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
BgReading last_bg = iobCobCalculatorPlugin.lastBg();
GlucoseValue last_bg = iobCobCalculatorPlugin.lastBg();
if (last_bg == null) return;
List<BgReading> graph_bgs = MainApp.getDbHelper().getBgreadingsDataFromTime(startTime, true);
List<GlucoseValue> graph_bgs = repository.compatGetBgReadingsDataFromTime(startTime, true).blockingGet();
GlucoseStatus glucoseStatus = new GlucoseStatus(injector).getGlucoseStatusData(true);
if (!graph_bgs.isEmpty()) {
@ -395,7 +397,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
return;
}
final ArrayList<DataMap> dataMaps = new ArrayList<>(graph_bgs.size());
for (BgReading bg : graph_bgs) {
for (GlucoseValue bg : graph_bgs) {
DataMap dataMap = dataMapSingleBG(bg, glucoseStatus);
if (dataMap != null) {
dataMaps.add(dataMap);
@ -535,14 +537,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
}
final LoopPlugin.LastRun finalLastRun = loopPlugin.getLastRun();
if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().hasPredictions && finalLastRun.getConstraintsProcessed() != null) {
List<BgReading> predArray = finalLastRun.getConstraintsProcessed().getPredictions();
if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().getHasPredictions() && finalLastRun.getConstraintsProcessed() != null) {
List<GlucoseValueDataPoint> predArray = finalLastRun.getConstraintsProcessed().getPredictions();
if (!predArray.isEmpty()) {
final String units = profileFunction.getUnits();
for (BgReading bg : predArray) {
if (bg.value < 40) continue;
predictions.add(predictionMap(bg.date, bg.value, bg.getPredectionColor()));
for (GlucoseValueDataPoint bg : predArray) {
if (bg.getData().getValue() < 40) continue;
predictions.add(predictionMap(bg.getData().getTimestamp(), bg.getData().getValue(), bg.getPredictionColor()));
}
}
}

View file

@ -11,19 +11,19 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.sharedPreferences.SP
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
import javax.inject.Singleton
@ -33,6 +33,7 @@ class StatusLinePlugin @Inject constructor(
private val sp: SP,
private val profileFunction: ProfileFunction,
resourceHelper: ResourceHelper,
private val aapsSchedulers: AapsSchedulers,
private val context: Context,
private val fabricPrivacy: FabricPrivacy,
private val activePlugin: ActivePluginProvider,
@ -56,6 +57,7 @@ class StatusLinePlugin @Inject constructor(
private var lastLoopStatus = false
companion object {
//broadcast related constants
@Suppress("SpellCheckingInspection")
private const val EXTRA_STATUSLINE = "com.eveningoutpost.dexdrip.Extras.Statusline"
@ -70,29 +72,29 @@ class StatusLinePlugin @Inject constructor(
override fun onStart() {
super.onStart()
disposable += rxBus.toObservable(EventRefreshOverview::class.java)
.observeOn(Schedulers.io())
.subscribe({ if (lastLoopStatus != loopPlugin.isEnabled(PluginType.LOOP)) sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ if (lastLoopStatus != loopPlugin.isEnabled(PluginType.LOOP)) sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventExtendedBolusChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventTempBasalChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventTreatmentChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventConfigBuilderChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
disposable += rxBus.toObservable(EventAppInitialized::class.java)
.observeOn(Schedulers.io())
.subscribe({ sendStatus() }) { fabricPrivacy.logException(it) }
.observeOn(aapsSchedulers.io)
.subscribe({ sendStatus() }, fabricPrivacy::logException)
}
override fun onStop() {

View file

@ -6,25 +6,38 @@ import android.view.View
import android.view.ViewGroup
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.InsulinFragmentBinding
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.utils.resources.ResourceHelper
import kotlinx.android.synthetic.main.insulin_fragment.*
import javax.inject.Inject
class InsulinFragment : DaggerFragment() {
@Inject lateinit var activePlugin: ActivePluginProvider
@Inject lateinit var resourceHelper: ResourceHelper
private var _binding: InsulinFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.insulin_fragment, container, false)
savedInstanceState: Bundle?): View {
_binding = InsulinFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onResume() {
super.onResume()
insulin_name?.text = activePlugin.activeInsulin.friendlyName
insulin_comment?.text = activePlugin.activeInsulin.comment
insulin_dia?.text = resourceHelper.gs(R.string.dia) + ": " + activePlugin.activeInsulin.dia + "h"
insulin_graph?.show(activePlugin.activeInsulin)
binding.name.text = activePlugin.activeInsulin.friendlyName
binding.comment.text = activePlugin.activeInsulin.comment
binding.dia.text = resourceHelper.gs(R.string.dia) + ": " + resourceHelper.gs(R.string.format_hours, activePlugin.activeInsulin.dia)
binding.graph.show(activePlugin.activeInsulin)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -8,7 +8,7 @@ import java.util.List;
import javax.inject.Inject;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.utils.DateUtil;
@ -71,7 +71,7 @@ public class GlucoseStatus {
synchronized (iobCobCalculatorPlugin.getDataLock()) {
List<BgReading> data = iobCobCalculatorPlugin.getBgReadings();
List<GlucoseValue> data = iobCobCalculatorPlugin.getBgReadings();
if (data == null) {
aapsLogger.debug(LTag.GLUCOSE, "data=null");
@ -84,18 +84,18 @@ public class GlucoseStatus {
return null;
}
if (data.get(0).date < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
if (data.get(0).getTimestamp() < DateUtil.now() - 7 * 60 * 1000L && !allowOldData) {
aapsLogger.debug(LTag.GLUCOSE, "olddata");
return null;
}
BgReading now = data.get(0);
long now_date = now.date;
GlucoseValue now = data.get(0);
long now_date = now.getTimestamp();
double change;
if (sizeRecords == 1) {
GlucoseStatus status = new GlucoseStatus(injector);
status.glucose = now.value;
status.glucose = now.getValue();
status.noise = 0d;
status.short_avgdelta = 0d;
status.delta = 0d;
@ -112,18 +112,18 @@ public class GlucoseStatus {
ArrayList<Double> long_deltas = new ArrayList<>();
// Use the latest sgv value in the now calculations
now_value_list.add(now.value);
now_value_list.add(now.getValue());
for (int i = 1; i < sizeRecords; i++) {
if (data.get(i).value > 38) {
BgReading then = data.get(i);
long then_date = then.date;
if (data.get(i).getValue() > 38) {
GlucoseValue then = data.get(i);
long then_date = then.getTimestamp();
double avgdelta;
long minutesago;
minutesago = Math.round((now_date - then_date) / (1000d * 60));
// multiply by 5 to get the same units as delta, i.e. mg/dL/5m
change = now.value - then.value;
change = now.getValue() - then.getValue();
avgdelta = change / minutesago * 5;
aapsLogger.debug(LTag.GLUCOSE, then.toString() + " minutesago=" + minutesago + " avgdelta=" + avgdelta);
@ -131,8 +131,8 @@ public class GlucoseStatus {
// use the average of all data points in the last 2.5m for all further "now" calculations
if (0 < minutesago && minutesago < 2.5) {
// Keep and average all values within the last 2.5 minutes
now_value_list.add(then.value);
now.value = average(now_value_list);
now_value_list.add(then.getValue());
now.setValue(average(now_value_list));
// short_deltas are calculated from everything ~5-15 minutes ago
} else if (2.5 < minutesago && minutesago < 17.5) {
//console.error(minutesago, avgdelta);
@ -152,7 +152,7 @@ public class GlucoseStatus {
}
GlucoseStatus status = new GlucoseStatus(injector);
status.glucose = now.value;
status.glucose = now.getValue();
status.date = now_date;
status.noise = 0d; //for now set to nothing as not all CGMs report noise

View file

@ -1,9 +1,9 @@
package info.nightscout.androidaps.plugins.iob.iobCobCalculator
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.database.entities.GlucoseValue
class InMemoryGlucoseValue @JvmOverloads constructor(var timestamp: Long = 0L, var value: Double = 0.0, var interpolated : Boolean = false) {
class InMemoryGlucoseValue @JvmOverloads constructor(var timestamp: Long = 0L, var value: Double = 0.0, var interpolated: Boolean = false) {
constructor(gv: BgReading) : this(gv.date, gv.value)
constructor(gv: GlucoseValue) : this(gv.timestamp, gv.value)
// var generated : value doesn't correspond to real value with timestamp close to real BG
}

View file

@ -10,19 +10,21 @@ import org.json.JSONArray;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.android.HasAndroidInjector;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.MealData;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.database.AppRepository;
import info.nightscout.androidaps.database.entities.GlucoseValue;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.events.EventAppInitialized;
import info.nightscout.androidaps.events.EventConfigBuilderChange;
@ -34,32 +36,32 @@ import info.nightscout.androidaps.interfaces.IobCobCalculatorInterface;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryData;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;
import info.nightscout.androidaps.utils.FabricPrivacy;
import info.nightscout.androidaps.utils.T;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
import info.nightscout.androidaps.utils.sharedPreferences.SP;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import static info.nightscout.androidaps.utils.DateUtil.now;
@Singleton
public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculatorInterface {
private final HasAndroidInjector injector;
private final AapsSchedulers aapsSchedulers;
private final SP sp;
private final RxBusWrapper rxBus;
private final ResourceHelper resourceHelper;
@ -71,6 +73,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
private final SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin;
private final FabricPrivacy fabricPrivacy;
private final DateUtil dateUtil;
private final AppRepository repository;
private final CompositeDisposable disposable = new CompositeDisposable();
@ -79,14 +82,14 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
private LongSparseArray<AutosensData> autosensDataTable = new LongSparseArray<>(); // oldest at index 0
private LongSparseArray<BasalData> basalDataTable = new LongSparseArray<>(); // oldest at index 0
private volatile List<GlucoseValue> bgReadings = null; // newest at index 0
private volatile List<InMemoryGlucoseValue> bucketed_data = null;
// we need to make sure that bucketed_data will always have the same timestamp for correct use of cached values
// once referenceTime != null all bucketed data should be (x * 5min) from referenceTime
Long referenceTime = null;
private Boolean lastUsed5minCalculation = null; // true if used 5min bucketed data
private volatile List<BgReading> bgReadings = null; // newest at index 0
private volatile List<InMemoryGlucoseValue> bucketed_data = null;
private final Object dataLock = new Object();
boolean stopCalculationTrigger = false;
@ -96,6 +99,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
public IobCobCalculatorPlugin(
HasAndroidInjector injector,
AAPSLogger aapsLogger,
AapsSchedulers aapsSchedulers,
RxBusWrapper rxBus,
SP sp,
ResourceHelper resourceHelper,
@ -106,7 +110,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
SensitivityAAPSPlugin sensitivityAAPSPlugin,
SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin,
FabricPrivacy fabricPrivacy,
DateUtil dateUtil
DateUtil dateUtil,
AppRepository repository
) {
super(new PluginDescription()
.mainType(PluginType.GENERAL)
@ -117,6 +122,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
aapsLogger, resourceHelper, injector
);
this.injector = injector;
this.aapsSchedulers = aapsSchedulers;
this.sp = sp;
this.rxBus = rxBus;
this.resourceHelper = resourceHelper;
@ -128,6 +134,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
this.sensitivityWeightedAveragePlugin = sensitivityWeightedAveragePlugin;
this.fabricPrivacy = fabricPrivacy;
this.dateUtil = dateUtil;
this.repository = repository;
}
@Override
@ -136,7 +143,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
// EventConfigBuilderChange
disposable.add(rxBus
.toObservable(EventConfigBuilderChange.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
stopCalculation("onEventConfigBuilderChange");
synchronized (dataLock) {
@ -149,7 +156,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
// EventNewBasalProfile
disposable.add(rxBus
.toObservable(EventNewBasalProfile.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
if (event == null) { // on init no need of reset
return;
@ -165,7 +172,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
// EventNewBG .... cannot be used for invalidating because only event with last BG is fired
disposable.add(rxBus
.toObservable(EventNewBG.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.debounce(1L, TimeUnit.SECONDS)
.subscribe(event -> {
stopCalculation("onEventNewBG");
runCalculation("onEventNewBG", System.currentTimeMillis(), true, true, event);
@ -174,7 +182,7 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
// EventPreferenceChange
disposable.add(rxBus
.toObservable(EventPreferenceChange.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> {
if (event.isChanged(resourceHelper, R.string.key_openapsama_autosens_period) ||
event.isChanged(resourceHelper, R.string.key_age) ||
@ -197,19 +205,19 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
// EventAppInitialized
disposable.add(rxBus
.toObservable(EventAppInitialized.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> runCalculation("onEventAppInitialized", System.currentTimeMillis(), true, true, event), fabricPrivacy::logException)
);
// EventNewHistoryData
disposable.add(rxBus
.toObservable(EventNewHistoryData.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> newHistoryData(event, false), fabricPrivacy::logException)
);
// EventNewHistoryBgData
disposable.add(rxBus
.toObservable(EventNewHistoryBgData.class)
.observeOn(Schedulers.io())
.observeOn(aapsSchedulers.getIo())
.subscribe(event -> newHistoryData(new EventNewHistoryData(event.getTimestamp()), true), fabricPrivacy::logException)
);
}
@ -224,11 +232,11 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
return autosensDataTable;
}
public List<BgReading> getBgReadings() {
public List<GlucoseValue> getBgReadings() {
return bgReadings;
}
public void setBgReadings(List<BgReading> bgReadings) {
public void setBgReadings(List<GlucoseValue> bgReadings) {
this.bgReadings = bgReadings;
}
@ -269,10 +277,10 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
if (DateUtil.isCloseToNow(to)) {
// if close to now expect there can be some readings with time in close future (caused by wrong time setting)
// so read all records
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, false);
bgReadings = repository.compatGetBgReadingsDataFromTime(start, false).blockingGet();
getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start));
} else {
bgReadings = MainApp.getDbHelper().getBgreadingsDataFromTime(start, to, false);
bgReadings = repository.compatGetBgReadingsDataFromTime(start, to, false).blockingGet();
getAapsLogger().debug(LTag.AUTOSENS, "BG data loaded. Size: " + bgReadings.size() + " Start date: " + dateUtil.dateAndTimeString(start) + " End date: " + dateUtil.dateAndTimeString(to));
}
}
@ -284,8 +292,8 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
}
long totalDiff = 0;
for (int i = 1; i < bgReadings.size(); ++i) {
long bgTime = bgReadings.get(i).date;
long lastbgTime = bgReadings.get(i - 1).date;
long bgTime = bgReadings.get(i).getTimestamp();
long lastbgTime = bgReadings.get(i - 1).getTimestamp();
long diff = lastbgTime - bgTime;
diff %= T.mins(5).msecs();
if (diff > T.mins(2).plus(T.secs(30)).msecs())
@ -328,27 +336,27 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
}
@Nullable
public BgReading findNewer(long time) {
BgReading lastFound = bgReadings.get(0);
if (lastFound.date < time) return null;
public GlucoseValue findNewer(long time) {
GlucoseValue lastFound = bgReadings.get(0);
if (lastFound.getTimestamp() < time) return null;
for (int i = 1; i < bgReadings.size(); ++i) {
if (bgReadings.get(i).date == time) return bgReadings.get(i);
if (bgReadings.get(i).date > time) continue;
if (bgReadings.get(i).getTimestamp() == time) return bgReadings.get(i);
if (bgReadings.get(i).getTimestamp() > time) continue;
lastFound = bgReadings.get(i - 1);
if (bgReadings.get(i).date < time) break;
if (bgReadings.get(i).getTimestamp() < time) break;
}
return lastFound;
}
@Nullable
public BgReading findOlder(long time) {
BgReading lastFound = bgReadings.get(bgReadings.size() - 1);
if (lastFound.date > time) return null;
public GlucoseValue findOlder(long time) {
GlucoseValue lastFound = bgReadings.get(bgReadings.size() - 1);
if (lastFound.getTimestamp() > time) return null;
for (int i = bgReadings.size() - 2; i >= 0; --i) {
if (bgReadings.get(i).date == time) return bgReadings.get(i);
if (bgReadings.get(i).date < time) continue;
if (bgReadings.get(i).getTimestamp() == time) return bgReadings.get(i);
if (bgReadings.get(i).getTimestamp() < time) continue;
lastFound = bgReadings.get(i + 1);
if (bgReadings.get(i).date > time) break;
if (bgReadings.get(i).getTimestamp() > time) break;
}
return lastFound;
}
@ -360,25 +368,25 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
}
bucketed_data = new ArrayList<>();
long currentTime = bgReadings.get(0).date - bgReadings.get(0).date % T.mins(5).msecs();
long currentTime = bgReadings.get(0).getTimestamp() - bgReadings.get(0).getTimestamp() % T.mins(5).msecs();
currentTime = adjustToReferenceTime(currentTime);
getAapsLogger().debug("Adjusted time " + dateUtil.dateAndTimeAndSecondsString(currentTime));
//log.debug("First reading: " + new Date(currentTime).toLocaleString());
while (true) {
// test if current value is older than current time
BgReading newer = findNewer(currentTime);
BgReading older = findOlder(currentTime);
GlucoseValue newer = findNewer(currentTime);
GlucoseValue older = findOlder(currentTime);
if (newer == null || older == null)
break;
if (older.date == newer.date) { // direct hit
if (older.getTimestamp() == newer.getTimestamp()) { // direct hit
bucketed_data.add(new InMemoryGlucoseValue(newer));
} else {
double bgDelta = newer.value - older.value;
long timeDiffToNew = newer.date - currentTime;
double bgDelta = newer.getValue() - older.getValue();
long timeDiffToNew = newer.getTimestamp() - currentTime;
double currentBg = newer.value - (double) timeDiffToNew / (newer.date - older.date) * bgDelta;
double currentBg = newer.getValue() - (double) timeDiffToNew / (newer.getTimestamp() - older.getTimestamp()) * bgDelta;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(currentTime, Math.round(currentBg), true);
bucketed_data.add(newBgreading);
//log.debug("BG: " + newBgreading.value + " (" + new Date(newBgreading.date).toLocaleString() + ") Prev: " + older.value + " (" + new Date(older.date).toLocaleString() + ") Newer: " + newer.value + " (" + new Date(newer.date).toLocaleString() + ")");
@ -397,27 +405,27 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
bucketed_data = new ArrayList<>();
bucketed_data.add(new InMemoryGlucoseValue(bgReadings.get(0)));
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgReadings.get(0).date) + " lastbgTime: " + "none-first-value" + " " + bgReadings.get(0).toString());
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgReadings.get(0).getTimestamp()) + " lastbgTime: " + "none-first-value" + " " + bgReadings.get(0).toString());
int j = 0;
for (int i = 1; i < bgReadings.size(); ++i) {
long bgTime = bgReadings.get(i).date;
long lastbgTime = bgReadings.get(i - 1).date;
long bgTime = bgReadings.get(i).getTimestamp();
long lastbgTime = bgReadings.get(i - 1).getTimestamp();
//log.error("Processing " + i + ": " + new Date(bgTime).toString() + " " + bgReadings.get(i).value + " Previous: " + new Date(lastbgTime).toString() + " " + bgReadings.get(i - 1).value);
if (bgReadings.get(i).value < 39 || bgReadings.get(i - 1).value < 39) {
if (bgReadings.get(i).getValue() < 39 || bgReadings.get(i - 1).getValue() < 39) {
throw new IllegalStateException("<39");
}
long elapsed_minutes = (bgTime - lastbgTime) / (60 * 1000);
if (Math.abs(elapsed_minutes) > 8) {
// interpolate missing data points
double lastbg = bgReadings.get(i - 1).value;
double lastbg = bgReadings.get(i - 1).getValue();
elapsed_minutes = Math.abs(elapsed_minutes);
//console.error(elapsed_minutes);
long nextbgTime;
while (elapsed_minutes > 5) {
nextbgTime = lastbgTime - 5 * 60 * 1000;
j++;
double gapDelta = bgReadings.get(i).value - lastbg;
double gapDelta = bgReadings.get(i).getValue() - lastbg;
//console.error(gapDelta, lastbg, elapsed_minutes);
double nextbg = lastbg + (5d / elapsed_minutes * gapDelta);
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(nextbgTime, Math.round(nextbg), true);
@ -430,16 +438,16 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
lastbgTime = nextbgTime;
}
j++;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).value);
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).getValue());
bucketed_data.add(newBgreading);
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else if (Math.abs(elapsed_minutes) > 2) {
j++;
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).value);
InMemoryGlucoseValue newBgreading = new InMemoryGlucoseValue(bgTime, bgReadings.get(i).getValue());
bucketed_data.add(newBgreading);
getAapsLogger().debug(LTag.AUTOSENS, "Adding. bgTime: " + DateUtil.toISOString(bgTime) + " lastbgTime: " + DateUtil.toISOString(lastbgTime) + " " + newBgreading.toString());
} else {
bucketed_data.get(j).setValue((bucketed_data.get(j).getValue() + bgReadings.get(i).value) / 2);
bucketed_data.get(j).setValue((bucketed_data.get(j).getValue() + bgReadings.get(i).getValue()) / 2);
//log.error("***** Average");
}
}
@ -911,14 +919,14 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
* Return last BgReading from database or null if db is empty
*/
@Nullable
public BgReading lastBg() {
List<BgReading> bgList = getBgReadings();
public GlucoseValue lastBg() {
List<GlucoseValue> bgList = getBgReadings();
if (bgList == null)
return null;
for (int i = 0; i < bgList.size(); i++)
if (bgList.get(i).value >= 39)
if (bgList.get(i).getValue() >= 39)
return bgList.get(i);
return null;
}
@ -928,13 +936,13 @@ public class IobCobCalculatorPlugin extends PluginBase implements IobCobCalculat
* or null if older
*/
@Nullable
public BgReading actualBg() {
BgReading lastBg = lastBg();
public GlucoseValue actualBg() {
GlucoseValue lastBg = lastBg();
if (lastBg == null)
return null;
if (lastBg.date > System.currentTimeMillis() - 9 * 60 * 1000)
if (lastBg.getTimestamp() > System.currentTimeMillis() - 9 * 60 * 1000)
return lastBg;
return null;

View file

@ -18,15 +18,14 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
@ -35,7 +34,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutos
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;

View file

@ -16,15 +16,14 @@ import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.db.BgReading;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.events.Event;
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.interfaces.ProfileFunction;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.data.AutosensData;
@ -33,7 +32,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutos
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
import info.nightscout.androidaps.db.Treatment;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.DecimalFormatter;

View file

@ -12,23 +12,23 @@ import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.databinding.LocalprofileFragmentBinding
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.insulin.InsulinOrefBasePlugin.Companion.MIN_DIA
import info.nightscout.androidaps.plugins.profile.local.events.EventLocalProfileChanged
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.localprofile_fragment.*
import java.text.DecimalFormat
import javax.inject.Inject
class LocalProfileFragment : DaggerFragment() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var resourceHelper: ResourceHelper
@ -37,6 +37,7 @@ class LocalProfileFragment : DaggerFragment() {
@Inject lateinit var localProfilePlugin: LocalProfilePlugin
@Inject lateinit var hardLimits: HardLimits
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var aapsSchedulers: AapsSchedulers
private var disposable: CompositeDisposable = CompositeDisposable()
@ -52,8 +53,8 @@ class LocalProfileFragment : DaggerFragment() {
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
localProfilePlugin.currentProfile()?.dia = SafeParse.stringToDouble(localprofile_dia.text.toString())
localProfilePlugin.currentProfile()?.name = localprofile_name.text.toString()
localProfilePlugin.currentProfile()?.dia = SafeParse.stringToDouble(binding.dia.text.toString())
localProfilePlugin.currentProfile()?.name = binding.name.text.toString()
doEdit()
}
}
@ -64,36 +65,42 @@ class LocalProfileFragment : DaggerFragment() {
return "" + DecimalFormatter.to2Decimal(sum) + resourceHelper.gs(R.string.insulin_unit_shortname)
}
private var _binding: LocalprofileFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.localprofile_fragment, container, false)
savedInstanceState: Bundle?): View {
_binding = LocalprofileFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// activate DIA tab
processVisibilityOnClick(dia_tab)
localprofile_dia_placeholder.visibility = View.VISIBLE
binding.diaPlaceholder.visibility = View.VISIBLE
// setup listeners
dia_tab.setOnClickListener {
binding.diaTab.setOnClickListener {
processVisibilityOnClick(it)
localprofile_dia_placeholder.visibility = View.VISIBLE
binding.diaPlaceholder.visibility = View.VISIBLE
}
ic_tab.setOnClickListener {
binding.icTab.setOnClickListener {
processVisibilityOnClick(it)
localprofile_ic.visibility = View.VISIBLE
binding.ic.visibility = View.VISIBLE
}
isf_tab.setOnClickListener {
binding.isfTab.setOnClickListener {
processVisibilityOnClick(it)
localprofile_isf.visibility = View.VISIBLE
binding.isf.visibility = View.VISIBLE
}
basal_tab.setOnClickListener {
binding.basalTab.setOnClickListener {
processVisibilityOnClick(it)
localprofile_basal.visibility = View.VISIBLE
binding.basal.visibility = View.VISIBLE
}
target_tab.setOnClickListener {
binding.targetTab.setOnClickListener {
processVisibilityOnClick(it)
localprofile_target.visibility = View.VISIBLE
binding.target.visibility = View.VISIBLE
}
}
@ -103,23 +110,23 @@ class LocalProfileFragment : DaggerFragment() {
val currentProfile = localProfilePlugin.currentProfile() ?: return
val units = if (currentProfile.mgdl) Constants.MGDL else Constants.MMOL
localprofile_name.removeTextChangedListener(textWatch)
localprofile_name.setText(currentProfile.name)
localprofile_name.addTextChangedListener(textWatch)
localprofile_dia.setParams(currentProfile.dia, hardLimits.minDia(), hardLimits.maxDia(), 0.1, DecimalFormat("0.0"), false, localprofile_save, textWatch)
localprofile_dia.tag = "LP_DIA"
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.localprofile_ic, "IC", resourceHelper.gs(R.string.ic_label), currentProfile.ic, null, hardLimits.minIC(), hardLimits.maxIC(), 0.1, DecimalFormat("0.0"), save)
basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.localprofile_basal, "BASAL", resourceHelper.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, pumpDescription.basalMinimumRate, 10.0, 0.01, DecimalFormat("0.00"), save)
binding.name.removeTextChangedListener(textWatch)
binding.name.setText(currentProfile.name)
binding.name.addTextChangedListener(textWatch)
binding.dia.setParams(currentProfile.dia, hardLimits.minDia(), hardLimits.maxDia(), 0.1, DecimalFormat("0.0"), false, binding.save, textWatch)
binding.dia.tag = "LP_DIA"
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.ic, "IC", resourceHelper.gs(R.string.ic_label), currentProfile.ic, null, hardLimits.minIC(), hardLimits.maxIC(), 0.1, DecimalFormat("0.0"), save)
basalView = TimeListEdit(context, aapsLogger, dateUtil, view, R.id.basal, "BASAL", resourceHelper.gs(R.string.basal_label) + ": " + sumLabel(), currentProfile.basal, null, pumpDescription.basalMinimumRate, 10.0, 0.01, DecimalFormat("0.00"), save)
if (units == Constants.MGDL) {
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.localprofile_isf, "ISF", resourceHelper.gs(R.string.isf_label), currentProfile.isf, null, hardLimits.MINISF, hardLimits.MAXISF, 1.0, DecimalFormat("0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.localprofile_target, "TARGET", resourceHelper.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble(), 1.0, DecimalFormat("0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf, "ISF", resourceHelper.gs(R.string.isf_label), currentProfile.isf, null, hardLimits.MINISF, hardLimits.MAXISF, 1.0, DecimalFormat("0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target, "TARGET", resourceHelper.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble(), 1.0, DecimalFormat("0"), save)
} else {
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.localprofile_isf, "ISF", resourceHelper.gs(R.string.isf_label), currentProfile.isf, null, Profile.fromMgdlToUnits(hardLimits.MINISF, Constants.MMOL), Profile.fromMgdlToUnits(hardLimits.MAXISF, Constants.MMOL), 0.1, DecimalFormat("0.0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.localprofile_target, "TARGET", resourceHelper.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, Profile.fromMgdlToUnits(hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), Constants.MMOL), Profile.fromMgdlToUnits(hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble(), Constants.MMOL), 0.1, DecimalFormat("0.0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.isf, "ISF", resourceHelper.gs(R.string.isf_label), currentProfile.isf, null, Profile.fromMgdlToUnits(hardLimits.MINISF, Constants.MMOL), Profile.fromMgdlToUnits(hardLimits.MAXISF, Constants.MMOL), 0.1, DecimalFormat("0.0"), save)
TimeListEdit(context, aapsLogger, dateUtil, view, R.id.target, "TARGET", resourceHelper.gs(R.string.target_label), currentProfile.targetLow, currentProfile.targetHigh, Profile.fromMgdlToUnits(hardLimits.VERY_HARD_LIMIT_TARGET_BG[0].toDouble(), Constants.MMOL), Profile.fromMgdlToUnits(hardLimits.VERY_HARD_LIMIT_TARGET_BG[1].toDouble(), Constants.MMOL), 0.1, DecimalFormat("0.0"), save)
}
// Spinner
spinner = SpinnerHelper(view?.findViewById(R.id.localprofile_spinner))
spinner = SpinnerHelper(binding.spinner)
val profileList: ArrayList<CharSequence> = localProfilePlugin.profile?.getProfileList()
?: ArrayList()
context?.let { context ->
@ -134,10 +141,10 @@ class LocalProfileFragment : DaggerFragment() {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (localProfilePlugin.isEdited) {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.doyouwantswitchprofile), Runnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.doyouwantswitchprofile), {
localProfilePlugin.currentProfileIndex = position
build()
}, Runnable {
}, {
spinner?.setSelection(localProfilePlugin.currentProfileIndex)
})
}
@ -148,7 +155,7 @@ class LocalProfileFragment : DaggerFragment() {
}
})
localprofile_profile_add.setOnClickListener {
binding.profileAdd.setOnClickListener {
if (localProfilePlugin.isEdited) {
activity?.let { OKDialog.show(it, "", resourceHelper.gs(R.string.saveorresetchangesfirst)) }
} else {
@ -157,7 +164,7 @@ class LocalProfileFragment : DaggerFragment() {
}
}
localprofile_profile_clone.setOnClickListener {
binding.profileClone.setOnClickListener {
if (localProfilePlugin.isEdited) {
activity?.let { OKDialog.show(it, "", resourceHelper.gs(R.string.saveorresetchangesfirst)) }
} else {
@ -166,9 +173,9 @@ class LocalProfileFragment : DaggerFragment() {
}
}
localprofile_profile_remove.setOnClickListener {
binding.profileRemove.setOnClickListener {
activity?.let { activity ->
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.deletecurrentprofile), Runnable {
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.deletecurrentprofile), {
localProfilePlugin.removeCurrentProfile()
build()
}, null)
@ -176,23 +183,23 @@ class LocalProfileFragment : DaggerFragment() {
}
// this is probably not possible because it leads to invalid profile
// if (!pumpDescription.isTempBasalCapable) localprofile_basal.visibility = View.GONE
// if (!pumpDescription.isTempBasalCapable) binding.basal.visibility = View.GONE
@Suppress("SetTextI18n")
localprofile_units.text = resourceHelper.gs(R.string.units_colon) + " " + (if (currentProfile.mgdl) resourceHelper.gs(R.string.mgdl) else resourceHelper.gs(R.string.mmol))
binding.units.text = resourceHelper.gs(R.string.units_colon) + " " + (if (currentProfile.mgdl) resourceHelper.gs(R.string.mgdl) else resourceHelper.gs(R.string.mmol))
localprofile_profileswitch.setOnClickListener {
binding.profileswitch.setOnClickListener {
ProfileSwitchDialog()
.also { it.arguments = Bundle().also { bundle -> bundle.putInt("profileIndex", localProfilePlugin.currentProfileIndex) } }
.show(childFragmentManager, "NewNSTreatmentDialog")
}
localprofile_reset.setOnClickListener {
binding.reset.setOnClickListener {
localProfilePlugin.loadSettings()
build()
}
localprofile_save.setOnClickListener {
binding.save.setOnClickListener {
if (!localProfilePlugin.isValidEditState()) {
return@setOnClickListener //Should not happen as saveButton should not be visible if not valid
}
@ -207,9 +214,8 @@ class LocalProfileFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventLocalProfileChanged::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ build() }, { fabricPrivacy.logException(it) }
)
.observeOn(aapsSchedulers.main)
.subscribe({ build() },fabricPrivacy::logException)
build()
}
@ -219,13 +225,19 @@ class LocalProfileFragment : DaggerFragment() {
disposable.clear()
}
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
fun doEdit() {
localProfilePlugin.isEdited = true
updateGUI()
}
fun updateGUI() {
if (localprofile_profileswitch == null) return
if (_binding == null) return
val isValid = localProfilePlugin.isValidEditState()
val isEdited = localProfilePlugin.isEdited
if (isValid) {
@ -233,37 +245,37 @@ class LocalProfileFragment : DaggerFragment() {
if (isEdited) {
//edited profile -> save first
localprofile_profileswitch.visibility = View.GONE
localprofile_save.visibility = View.VISIBLE
binding.profileswitch.visibility = View.GONE
binding.save.visibility = View.VISIBLE
} else {
localprofile_profileswitch.visibility = View.VISIBLE
localprofile_save.visibility = View.GONE
binding.profileswitch.visibility = View.VISIBLE
binding.save.visibility = View.GONE
}
} else {
this.view?.setBackgroundColor(resourceHelper.gc(R.color.error_background))
localprofile_profileswitch.visibility = View.GONE
localprofile_save.visibility = View.GONE //don't save an invalid profile
binding.profileswitch.visibility = View.GONE
binding.save.visibility = View.GONE //don't save an invalid profile
}
//Show reset button if data was edited
if (isEdited) {
localprofile_reset.visibility = View.VISIBLE
binding.reset.visibility = View.VISIBLE
} else {
localprofile_reset.visibility = View.GONE
binding.reset.visibility = View.GONE
}
}
private fun processVisibilityOnClick(selected: View) {
dia_tab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
ic_tab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
isf_tab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
basal_tab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
target_tab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
binding.diaTab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
binding.icTab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
binding.isfTab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
binding.basalTab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
binding.targetTab.setBackgroundColor(resourceHelper.gc(R.color.defaultbackground))
selected.setBackgroundColor(resourceHelper.gc(R.color.tabBgColorSelected))
localprofile_dia_placeholder.visibility = View.GONE
localprofile_ic.visibility = View.GONE
localprofile_isf.visibility = View.GONE
localprofile_basal.visibility = View.GONE
localprofile_target.visibility = View.GONE
binding.diaPlaceholder.visibility = View.GONE
binding.ic.visibility = View.GONE
binding.isf.visibility = View.GONE
binding.basal.visibility = View.GONE
binding.target.visibility = View.GONE
}
}

View file

@ -19,7 +19,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import io.reactivex.android.schedulers.AndroidSchedulers
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.disposables.CompositeDisposable
import javax.inject.Inject
@ -31,6 +31,7 @@ class NSProfileFragment : DaggerFragment() {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var nsProfilePlugin: NSProfilePlugin
@Inject lateinit var aapsSchedulers: AapsSchedulers
private var disposable: CompositeDisposable = CompositeDisposable()
@ -117,8 +118,8 @@ class NSProfileFragment : DaggerFragment() {
super.onResume()
disposable += rxBus
.toObservable(EventNSProfileUpdateGUI::class.java)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ updateGUI() }, { fabricPrivacy.logException(it) })
.observeOn(aapsSchedulers.main)
.subscribe({ updateGUI() }, fabricPrivacy::logException)
updateGUI()
}

Some files were not shown because too many files have changed in this diff Show more