From 312d863e381891f65d9107f80b006f8b10a7704e Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sun, 5 Apr 2020 10:04:21 +0200 Subject: [PATCH] OverviewFragment refactor --- .../androidaps/db/CareportalEvent.java | 4 - .../nightscout/androidaps/logging/LTag.kt | 1 - .../plugins/aps/loop/LoopFragment.kt | 2 +- .../plugins/aps/loop/LoopPlugin.java | 12 +- .../dataBroadcaster/DataBroadcastPlugin.kt | 7 +- .../plugins/general/nsclient/NSUpload.java | 2 +- .../general/overview/OverviewFragment.java | 1184 ----------------- .../general/overview/OverviewFragment.kt | 825 ++++++++++++ .../plugins/general/overview/OverviewMenus.kt | 41 +- .../general/overview/StatusLightHandler.kt | 18 +- .../general/overview/graphData/GraphData.kt | 2 +- .../general/wear/ActionStringHandler.kt | 18 +- .../nightscout/androidaps/utils/OKDialog.kt | 2 - .../utils/resources/ResourceHelper.kt | 1 + .../resources/ResourceHelperImplementation.kt | 2 + 15 files changed, 881 insertions(+), 1240 deletions(-) delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt diff --git a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java index 9912644797..bb412703f4 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/db/CareportalEvent.java @@ -107,10 +107,6 @@ public class CareportalEvent implements DataPointWithLabelInterface, Interval { return diff.get(TimeUnit.DAYS) + days + diff.get(TimeUnit.HOURS) + hours; } - public String age() { - return age(OverviewFragment.shorttextmode); - } - public boolean isOlderThan(double hours) { return getHoursFromStart() > hours; } diff --git a/app/src/main/java/info/nightscout/androidaps/logging/LTag.kt b/app/src/main/java/info/nightscout/androidaps/logging/LTag.kt index fc88377d6b..6e288a2bec 100644 --- a/app/src/main/java/info/nightscout/androidaps/logging/LTag.kt +++ b/app/src/main/java/info/nightscout/androidaps/logging/LTag.kt @@ -17,7 +17,6 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires LOCATION("LOCATION"), NOTIFICATION("NOTIFICATION"), NSCLIENT("NSCLIENT"), - OVERVIEW("OVERVIEW", defaultValue = false), PUMP("PUMP"), PUMPBTCOMM("PUMPBTCOMM", defaultValue = false), PUMPCOMM("PUMPCOMM"), diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt index 5abe8c354b..8463e8f133 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopFragment.kt @@ -81,7 +81,7 @@ class LoopFragment : DaggerFragment() { loop_request?.text = it.request?.toSpanned() ?: "" loop_constraintsprocessed?.text = it.constraintsProcessed?.toSpanned() ?: "" loop_source?.text = it.source ?: "" - loop_lastrun?.text = it.lastAPSRun?.let { lastRun -> DateUtil.dateAndTimeString(lastRun.time) } + loop_lastrun?.text = DateUtil.dateAndTimeString(it.lastAPSRun) ?: "" loop_smbrequest_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBRequest) loop_smbexecution_time?.text = DateUtil.dateAndTimeAndSecondsString(it.lastSMBEnact) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java index 79c3f5cd33..30c8603b71 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/loop/LoopPlugin.java @@ -13,6 +13,7 @@ import android.os.SystemClock; import androidx.core.app.NotificationCompat; +import org.jetbrains.annotations.Nullable; import org.json.JSONException; import org.json.JSONObject; @@ -104,7 +105,7 @@ public class LoopPlugin extends PluginBase { public PumpEnactResult tbrSetByPump = null; public PumpEnactResult smbSetByPump = null; public String source = null; - public Date lastAPSRun = null; + public long lastAPSRun = DateUtil.now(); public long lastTBREnact = 0; public long lastSMBEnact = 0; public long lastTBRRequest = 0; @@ -112,7 +113,7 @@ public class LoopPlugin extends PluginBase { public long lastOpenModeAccept; } - public LastRun lastRun = null; + @Nullable public LastRun lastRun = null; @Inject public LoopPlugin( @@ -381,7 +382,6 @@ public class LoopPlugin extends PluginBase { if (lastRun == null) lastRun = new LastRun(); lastRun.request = result; lastRun.constraintsProcessed = resultAfterConstraints; - lastRun.lastAPSRun = new Date(); lastRun.source = ((PluginBase) usedAPS).getName(); lastRun.tbrSetByPump = null; lastRun.smbSetByPump = null; @@ -423,7 +423,7 @@ public class LoopPlugin extends PluginBase { public void run() { if (result.enacted || result.success) { lastRun.tbrSetByPump = result; - lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime(); + lastRun.lastTBRRequest = lastRun.lastAPSRun; lastRun.lastTBREnact = DateUtil.now(); rxBus.send(new EventLoopUpdateGui()); applySMBRequest(resultAfterConstraints, new Callback() { @@ -432,7 +432,7 @@ public class LoopPlugin extends PluginBase { //Callback is only called if a bolus was acutally requested if (result.enacted || result.success) { lastRun.smbSetByPump = result; - lastRun.lastSMBRequest = lastRun.lastAPSRun.getTime(); + lastRun.lastSMBRequest = lastRun.lastAPSRun; lastRun.lastSMBEnact = DateUtil.now(); } else { new Thread(() -> { @@ -512,7 +512,7 @@ public class LoopPlugin extends PluginBase { public void run() { if (result.enacted) { lastRun.tbrSetByPump = result; - lastRun.lastTBRRequest = lastRun.lastAPSRun.getTime(); + lastRun.lastTBRRequest = lastRun.lastAPSRun; lastRun.lastTBREnact = DateUtil.now(); lastRun.lastOpenModeAccept = DateUtil.now(); NSUpload.uploadDeviceStatus(lp, iobCobCalculatorPlugin, profileFunction, activePlugin.getActivePump()); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt index d2c552c184..3b640a5496 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt @@ -125,7 +125,7 @@ class DataBroadcastPlugin @Inject constructor( private fun bgStatus(bundle: Bundle) { val lastBG: BgReading = iobCobCalculatorPlugin.lastBg() ?: return - val glucoseStatus = GlucoseStatus(injector).getGlucoseStatusData() ?: return + val glucoseStatus = GlucoseStatus(injector).glucoseStatusData ?: return bundle.putDouble("glucoseMgdl", lastBG.value) // last BG in mgdl bundle.putLong("glucoseTimeStamp", lastBG.date) // timestamp @@ -158,10 +158,9 @@ class DataBroadcastPlugin @Inject constructor( bundle.putInt("rigBattery", nsDeviceStatus.uploaderStatus.replace("%", "").trim { it <= ' ' }.toInt()) if (Config.APS && lazyLoopPlugin.get().lastRun?.lastTBREnact != 0L) { //we are AndroidAPS - bundle.putLong("suggestedTimeStamp", lazyLoopPlugin.get().lastRun?.lastAPSRun?.time - ?: -1L) + bundle.putLong("suggestedTimeStamp", lazyLoopPlugin.get().lastRun?.lastAPSRun ?: -1L) bundle.putString("suggested", lazyLoopPlugin.get().lastRun?.request?.json().toString()) - if (lazyLoopPlugin.get().lastRun.tbrSetByPump != null && lazyLoopPlugin.get().lastRun.tbrSetByPump.enacted) { + if (lazyLoopPlugin.get().lastRun?.tbrSetByPump != null && lazyLoopPlugin.get().lastRun?.tbrSetByPump?.enacted == true) { bundle.putLong("enactedTimeStamp", lazyLoopPlugin.get().lastRun?.lastTBREnact ?: -1L) bundle.putString("enacted", lazyLoopPlugin.get().lastRun?.request?.json().toString()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java index c27b3896c9..3894c68ba2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/nsclient/NSUpload.java @@ -173,7 +173,7 @@ public class NSUpload { DeviceStatus deviceStatus = new DeviceStatus(); try { LoopPlugin.LastRun lastRun = loopPlugin.lastRun; - if (lastRun != null && lastRun.lastAPSRun.getTime() > System.currentTimeMillis() - 300 * 1000L) { + if (lastRun != null && lastRun.lastAPSRun > System.currentTimeMillis() - 300 * 1000L) { // do not send if result is older than 1 min APSResult apsResult = lastRun.request; apsResult.json().put("timestamp", DateUtil.toISOString(lastRun.lastAPSRun)); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java deleted file mode 100644 index d7bb8e35a5..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java +++ /dev/null @@ -1,1184 +0,0 @@ -package info.nightscout.androidaps.plugins.general.overview; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.NotificationManager; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Paint; -import android.os.Bundle; -import android.os.Handler; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.jjoe64.graphview.GraphView; - -import org.jetbrains.annotations.NotNull; - -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import dagger.android.support.DaggerFragment; -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.IobTotal; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.db.BgReading; -import info.nightscout.androidaps.db.ExtendedBolus; -import info.nightscout.androidaps.db.TempTarget; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.dialogs.CalibrationDialog; -import info.nightscout.androidaps.dialogs.CarbsDialog; -import info.nightscout.androidaps.dialogs.InsulinDialog; -import info.nightscout.androidaps.dialogs.TreatmentDialog; -import info.nightscout.androidaps.dialogs.WizardDialog; -import info.nightscout.androidaps.events.EventAcceptOpenLoopChange; -import info.nightscout.androidaps.events.EventCareportalEventChange; -import info.nightscout.androidaps.events.EventExtendedBolusChange; -import info.nightscout.androidaps.events.EventInitializationChanged; -import info.nightscout.androidaps.events.EventPreferenceChange; -import info.nightscout.androidaps.events.EventProfileNeedsUpdate; -import info.nightscout.androidaps.events.EventPumpStatusChanged; -import info.nightscout.androidaps.events.EventRefreshOverview; -import info.nightscout.androidaps.events.EventTempBasalChange; -import info.nightscout.androidaps.events.EventTempTargetChange; -import info.nightscout.androidaps.events.EventTreatmentChange; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.Constraint; -import info.nightscout.androidaps.interfaces.PluginType; -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.LoopPlugin; -import info.nightscout.androidaps.plugins.aps.loop.events.EventNewOpenLoopNotification; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; -import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus; -import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity; -import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData; -import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore; -import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress; -import info.nightscout.androidaps.plugins.source.DexcomPlugin; -import info.nightscout.androidaps.plugins.source.XdripPlugin; -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; -import info.nightscout.androidaps.queue.CommandQueue; -import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.DecimalFormatter; -import info.nightscout.androidaps.utils.DefaultValueHelper; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.OKDialog; -import info.nightscout.androidaps.utils.Profiler; -import info.nightscout.androidaps.utils.SingleClickButton; -import info.nightscout.androidaps.utils.T; -import info.nightscout.androidaps.utils.ToastUtils; -import info.nightscout.androidaps.utils.buildHelper.BuildHelper; -import info.nightscout.androidaps.utils.protection.ProtectionCheck; -import info.nightscout.androidaps.utils.resources.ResourceHelper; -import info.nightscout.androidaps.utils.sharedPreferences.SP; -import info.nightscout.androidaps.utils.wizard.BolusWizard; -import info.nightscout.androidaps.utils.wizard.QuickWizard; -import info.nightscout.androidaps.utils.wizard.QuickWizardEntry; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -public class OverviewFragment extends DaggerFragment implements View.OnClickListener, View.OnLongClickListener { - @Inject HasAndroidInjector injector; - @Inject AAPSLogger aapsLogger; - @Inject SP sp; - @Inject RxBusWrapper rxBus; - @Inject MainApp mainApp; - @Inject ResourceHelper resourceHelper; - @Inject DefaultValueHelper defaultValueHelper; - @Inject ProfileFunction profileFunction; - @Inject ConstraintChecker constraintChecker; - @Inject StatusLightHandler statusLightHandler; - @Inject NSDeviceStatus nsDeviceStatus; - @Inject LoopPlugin loopPlugin; - @Inject ConfigBuilderPlugin configBuilderPlugin; - @Inject ActivePluginProvider activePlugin; - @Inject TreatmentsPlugin treatmentsPlugin; - @Inject IobCobCalculatorPlugin iobCobCalculatorPlugin; - @Inject DexcomPlugin dexcomPlugin; - @Inject XdripPlugin xdripPlugin; - @Inject NotificationStore notificationStore; - @Inject ActionStringHandler actionStringHandler; - @Inject QuickWizard quickWizard; - @Inject BuildHelper buildHelper; - @Inject CommandQueue commandQueue; - @Inject ProtectionCheck protectionCheck; - @Inject FabricPrivacy fabricPrivacy; - @Inject OverviewMenus overviewMenus; - - private CompositeDisposable disposable = new CompositeDisposable(); - - TextView timeView; - TextView bgView; - TextView arrowView; - TextView sensitivityView; - TextView timeAgoView; - TextView timeAgoShortView; - TextView deltaView; - TextView deltaShortView; - TextView avgdeltaView; - TextView baseBasalView; - TextView extendedBolusView; - TextView activeProfileView; - TextView iobView; - TextView cobView; - TextView apsModeView; - TextView tempTargetView; - TextView pumpStatusView; - TextView pumpDeviceStatusView; - TextView openapsDeviceStatusView; - TextView uploaderDeviceStatusView; - TextView iobCalculationProgressView; - ConstraintLayout loopStatusLayout; - LinearLayout pumpStatusLayout; - GraphView bgGraph; - GraphView iobGraph; - - TextView iage; - TextView cage; - TextView sage; - TextView pbage; - - TextView iageView; - TextView cageView; - TextView reservoirView; - TextView sageView; - TextView batteryView; - LinearLayout statuslightsLayout; - - RecyclerView notificationsView; - LinearLayoutManager llm; - - SingleClickButton acceptTempButton; - - SingleClickButton treatmentButton; - SingleClickButton wizardButton; - SingleClickButton calibrationButton; - SingleClickButton insulinButton; - SingleClickButton carbsButton; - SingleClickButton cgmButton; - SingleClickButton quickWizardButton; - - boolean smallWidth; - boolean smallHeight; - - public static boolean shorttextmode = false; - - private int rangeToDisplay = 6; // for graph - - Handler sLoopHandler = new Handler(); - Runnable sRefreshLoop = null; - - public enum CHARTTYPE {PRE, BAS, IOB, COB, DEV, SEN, ACTPRIM, ACTSEC, DEVSLOPE} - - private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor(); - private static ScheduledFuture scheduledUpdate = null; - - public OverviewFragment() { - super(); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - //check screen width - final DisplayMetrics dm = new DisplayMetrics(); - getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); - int screen_width = dm.widthPixels; - int screen_height = dm.heightPixels; - smallWidth = screen_width <= Constants.SMALL_WIDTH; - smallHeight = screen_height <= Constants.SMALL_HEIGHT; - boolean landscape = screen_height < screen_width; - - View view; - - if (resourceHelper.gb(R.bool.isTablet) && (Config.NSCLIENT)) { - view = inflater.inflate(R.layout.overview_fragment_nsclient_tablet, container, false); - } else if (Config.NSCLIENT) { - view = inflater.inflate(R.layout.overview_fragment_nsclient, container, false); - shorttextmode = true; - } else if (smallHeight || landscape) { - view = inflater.inflate(R.layout.overview_fragment_landscape, container, false); - } else { - view = inflater.inflate(R.layout.overview_fragment, container, false); - } - - timeView = (TextView) view.findViewById(R.id.overview_time); - bgView = (TextView) view.findViewById(R.id.overview_bg); - arrowView = (TextView) view.findViewById(R.id.overview_arrow); - if (smallWidth) { - arrowView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 35); - } - sensitivityView = (TextView) view.findViewById(R.id.overview_sensitivity); - timeAgoView = (TextView) view.findViewById(R.id.overview_timeago); - timeAgoShortView = (TextView) view.findViewById(R.id.overview_timeagoshort); - deltaView = (TextView) view.findViewById(R.id.overview_delta); - deltaShortView = (TextView) view.findViewById(R.id.overview_deltashort); - avgdeltaView = (TextView) view.findViewById(R.id.overview_avgdelta); - baseBasalView = (TextView) view.findViewById(R.id.overview_basebasal); - extendedBolusView = (TextView) view.findViewById(R.id.overview_extendedbolus); - activeProfileView = (TextView) view.findViewById(R.id.overview_activeprofile); - pumpStatusView = (TextView) view.findViewById(R.id.overview_pumpstatus); - pumpDeviceStatusView = (TextView) view.findViewById(R.id.overview_pump); - openapsDeviceStatusView = (TextView) view.findViewById(R.id.overview_openaps); - uploaderDeviceStatusView = (TextView) view.findViewById(R.id.overview_uploader); - iobCalculationProgressView = (TextView) view.findViewById(R.id.overview_iobcalculationprogess); - loopStatusLayout = view.findViewById(R.id.overview_looplayout); - pumpStatusLayout = (LinearLayout) view.findViewById(R.id.overview_pumpstatuslayout); - - pumpStatusView.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder)); - - iobView = (TextView) view.findViewById(R.id.overview_iob); - cobView = (TextView) view.findViewById(R.id.overview_cob); - apsModeView = (TextView) view.findViewById(R.id.overview_apsmode); - tempTargetView = (TextView) view.findViewById(R.id.overview_temptarget); - - iage = view.findViewById(R.id.careportal_insulinage); - cage = view.findViewById(R.id.careportal_canulaage); - sage = view.findViewById(R.id.careportal_sensorage); - pbage = view.findViewById(R.id.careportal_pbage); - - iageView = view.findViewById(R.id.overview_insulinage); - cageView = view.findViewById(R.id.overview_canulaage); - reservoirView = view.findViewById(R.id.overview_reservoirlevel); - sageView = view.findViewById(R.id.overview_sensorage); - batteryView = view.findViewById(R.id.overview_batterylevel); - statuslightsLayout = view.findViewById(R.id.overview_statuslights); - - bgGraph = (GraphView) view.findViewById(R.id.overview_bggraph); - iobGraph = (GraphView) view.findViewById(R.id.overview_iobgraph); - - treatmentButton = (SingleClickButton) view.findViewById(R.id.overview_treatmentbutton); - treatmentButton.setOnClickListener(this); - wizardButton = (SingleClickButton) view.findViewById(R.id.overview_wizardbutton); - wizardButton.setOnClickListener(this); - insulinButton = (SingleClickButton) view.findViewById(R.id.overview_insulinbutton); - if (insulinButton != null) - insulinButton.setOnClickListener(this); - carbsButton = (SingleClickButton) view.findViewById(R.id.overview_carbsbutton); - if (carbsButton != null) - carbsButton.setOnClickListener(this); - acceptTempButton = (SingleClickButton) view.findViewById(R.id.overview_accepttempbutton); - if (acceptTempButton != null) - acceptTempButton.setOnClickListener(this); - quickWizardButton = (SingleClickButton) view.findViewById(R.id.overview_quickwizardbutton); - quickWizardButton.setOnClickListener(this); - quickWizardButton.setOnLongClickListener(this); - calibrationButton = (SingleClickButton) view.findViewById(R.id.overview_calibrationbutton); - if (calibrationButton != null) - calibrationButton.setOnClickListener(this); - cgmButton = (SingleClickButton) view.findViewById(R.id.overview_cgmbutton); - if (cgmButton != null) - cgmButton.setOnClickListener(this); - - notificationsView = (RecyclerView) view.findViewById(R.id.overview_notifications); - notificationsView.setHasFixedSize(false); - llm = new LinearLayoutManager(view.getContext()); - notificationsView.setLayoutManager(llm); - - int axisWidth = 50; - - if (dm.densityDpi <= 120) - axisWidth = 3; - else if (dm.densityDpi <= 160) - axisWidth = 10; - else if (dm.densityDpi <= 320) - axisWidth = 35; - else if (dm.densityDpi <= 420) - axisWidth = 50; - else if (dm.densityDpi <= 560) - axisWidth = 70; - else - axisWidth = 80; - - bgGraph.getGridLabelRenderer().setGridColor(resourceHelper.gc(R.color.graphgrid)); - bgGraph.getGridLabelRenderer().reloadStyles(); - iobGraph.getGridLabelRenderer().setGridColor(resourceHelper.gc(R.color.graphgrid)); - iobGraph.getGridLabelRenderer().reloadStyles(); - iobGraph.getGridLabelRenderer().setHorizontalLabelsVisible(false); - bgGraph.getGridLabelRenderer().setLabelVerticalWidth(axisWidth); - iobGraph.getGridLabelRenderer().setLabelVerticalWidth(axisWidth); - iobGraph.getGridLabelRenderer().setNumVerticalLabels(3); - - rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6); - - bgGraph.setOnLongClickListener(v -> { - rangeToDisplay += 6; - rangeToDisplay = rangeToDisplay > 24 ? 6 : rangeToDisplay; - sp.putInt(R.string.key_rangetodisplay, rangeToDisplay); - updateGUI("rangeChange"); - sp.putBoolean(R.string.key_objectiveusescale, true); - return false; - }); - - overviewMenus.setupChartMenu(view.findViewById(R.id.overview_chartMenuButton)); - - return view; - } - - @Override - public void onPause() { - super.onPause(); - disposable.clear(); - sLoopHandler.removeCallbacksAndMessages(null); - unregisterForContextMenu(apsModeView); - unregisterForContextMenu(activeProfileView); - unregisterForContextMenu(tempTargetView); - } - - @Override - public void onResume() { - super.onResume(); - disposable.add(rxBus - .toObservable(EventRefreshOverview.class) - .observeOn(Schedulers.io()) - .subscribe(eventOpenAPSUpdateGui -> scheduleUpdateGUI(eventOpenAPSUpdateGui.getFrom()), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventExtendedBolusChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventExtendedBolusChange"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventTempBasalChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventTempBasalChange"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventTreatmentChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventTreatmentChange"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventTempTargetChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventTempTargetChange"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventAcceptOpenLoopChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventAcceptOpenLoopChange"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventCareportalEventChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventCareportalEventChange"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventInitializationChanged.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventInitializationChanged"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventAutosensCalculationFinished.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventAutosensCalculationFinished"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventProfileNeedsUpdate.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventProfileNeedsUpdate"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventPreferenceChange.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventPreferenceChange"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventNewOpenLoopNotification.class) - .observeOn(Schedulers.io()) - .subscribe(event -> scheduleUpdateGUI("EventNewOpenLoopNotification"), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventPumpStatusChanged.class) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(event -> updatePumpStatus(event), - fabricPrivacy::logException - )); - disposable.add(rxBus - .toObservable(EventIobCalculationProgress.class) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(event -> { - if (iobCalculationProgressView != null) - iobCalculationProgressView.setText(event.getProgress()); - }, - fabricPrivacy::logException - )); - sRefreshLoop = () -> { - scheduleUpdateGUI("refreshLoop"); - sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); - }; - sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); - registerForContextMenu(apsModeView); - registerForContextMenu(activeProfileView); - registerForContextMenu(tempTargetView); - updateGUI("onResume"); - } - - - @Override - public void onCreateContextMenu(@NotNull ContextMenu menu, @NotNull View v, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - overviewMenus.createContextMenu(menu, v); - } - - @Override - public boolean onContextItemSelected(@NonNull MenuItem item) { - FragmentManager manager = getFragmentManager(); - if (manager != null && overviewMenus.onContextItemSelected(item, manager)) return true; - else return super.onContextItemSelected(item); - } - - @Override - public void onClick(View v) { - boolean xdrip = xdripPlugin.isEnabled(PluginType.BGSOURCE); - boolean dexcom = dexcomPlugin.isEnabled(PluginType.BGSOURCE); - - FragmentManager manager = getFragmentManager(); - // 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 (manager == null || manager.isStateSaved()) - return; - switch (v.getId()) { - case R.id.overview_accepttempbutton: - onClickAcceptTemp(); - break; - case R.id.overview_quickwizardbutton: - protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, this::onClickQuickwizard); - break; - case R.id.overview_wizardbutton: - protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new WizardDialog().show(manager, "WizardDialog")); - break; - case R.id.overview_calibrationbutton: - if (xdrip) { - CalibrationDialog calibrationDialog = new CalibrationDialog(); - calibrationDialog.show(manager, "CalibrationDialog"); - } else if (dexcom) { - try { - String packageName = dexcomPlugin.findDexcomPackageName(); - if (packageName != null) { - Intent i = new Intent("com.dexcom.cgm.activities.MeterEntryActivity"); - i.setPackage(packageName); - startActivity(i); - } else { - ToastUtils.showToastInUiThread(getActivity(), resourceHelper.gs(R.string.dexcom_app_not_installed)); - } - } catch (ActivityNotFoundException e) { - ToastUtils.showToastInUiThread(getActivity(), resourceHelper.gs(R.string.g5appnotdetected)); - } - } - break; - case R.id.overview_cgmbutton: - if (xdrip) - openCgmApp("com.eveningoutpost.dexdrip"); - else if (dexcom) { - String packageName = dexcomPlugin.findDexcomPackageName(); - if (packageName != null) { - openCgmApp(packageName); - } else { - ToastUtils.showToastInUiThread(getActivity(), resourceHelper.gs(R.string.dexcom_app_not_installed)); - } - } - break; - case R.id.overview_treatmentbutton: - protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new TreatmentDialog().show(manager, "Overview")); - break; - case R.id.overview_insulinbutton: - protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new InsulinDialog().show(manager, "Overview")); - break; - case R.id.overview_carbsbutton: - protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new CarbsDialog().show(manager, "Overview")); - break; - case R.id.overview_pumpstatus: - if (activePlugin.getActivePump().isSuspended() || !activePlugin.getActivePump().isInitialized()) - commandQueue.readStatus("RefreshClicked", null); - break; - } - - } - - private void openCgmApp(String packageName) { - PackageManager packageManager = getContext().getPackageManager(); - try { - Intent intent = packageManager.getLaunchIntentForPackage(packageName); - if (intent == null) { - throw new ActivityNotFoundException(); - } - intent.addCategory(Intent.CATEGORY_LAUNCHER); - getContext().startActivity(intent); - } catch (ActivityNotFoundException e) { - OKDialog.show(getContext(), "", resourceHelper.gs(R.string.error_starting_cgm)); - } - } - - @Override - public boolean onLongClick(View v) { - switch (v.getId()) { - case R.id.overview_quickwizardbutton: - Intent i = new Intent(v.getContext(), QuickWizardListActivity.class); - startActivity(i); - return true; - } - return false; - } - - private void onClickAcceptTemp() { - Profile profile = profileFunction.getProfile(); - Context context = getContext(); - - if (context == null) return; - - if (loopPlugin.isEnabled(PluginType.LOOP) && profile != null) { - loopPlugin.invoke("Accept temp button", false); - if (loopPlugin.lastRun != null && loopPlugin.lastRun.lastAPSRun != null && loopPlugin.lastRun.constraintsProcessed.isChangeRequested()) { - OKDialog.showConfirmation(context, resourceHelper.gs(R.string.pump_tempbasal_label), loopPlugin.lastRun.constraintsProcessed.toSpanned(), () -> { - aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL"); - hideTempRecommendation(); - clearNotification(); - loopPlugin.acceptChangeRequest(); - }); - } - } - } - - private void onClickQuickwizard() { - final BgReading actualBg = iobCobCalculatorPlugin.actualBg(); - final Profile profile = profileFunction.getProfile(); - final String profileName = profileFunction.getProfileName(); - final PumpInterface pump = activePlugin.getActivePump(); - - final QuickWizardEntry quickWizardEntry = quickWizard.getActive(); - if (quickWizardEntry != null && actualBg != null && profile != null) { - quickWizardButton.setVisibility(View.VISIBLE); - final BolusWizard wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true); - - if (wizard.getCalculatedTotalInsulin() > 0d && quickWizardEntry.carbs() > 0d) { - Integer carbsAfterConstraints = constraintChecker.applyCarbsConstraints(new Constraint<>(quickWizardEntry.carbs())).value(); - - if (Math.abs(wizard.getInsulinAfterConstraints() - wizard.getCalculatedTotalInsulin()) >= pump.getPumpDescription().pumpType.determineCorrectBolusStepSize(wizard.getInsulinAfterConstraints()) || !carbsAfterConstraints.equals(quickWizardEntry.carbs())) { - OKDialog.show(getContext(), resourceHelper.gs(R.string.treatmentdeliveryerror), resourceHelper.gs(R.string.constraints_violation) + "\n" + resourceHelper.gs(R.string.changeyourinput)); - return; - } - - wizard.confirmAndExecute(getContext()); - } - } - } - - private void hideTempRecommendation() { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(() -> { - if (acceptTempButton != null) - acceptTempButton.setVisibility(View.GONE); - }); - } - - private void clearNotification() { - NotificationManager notificationManager = - (NotificationManager) mainApp.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(Constants.notificationID); - - actionStringHandler.handleInitiate("cancelChangeRequest"); - } - - private void updatePumpStatus(EventPumpStatusChanged event) { - String status = event.getStatus(resourceHelper); - if (!status.equals("")) { - pumpStatusView.setText(status); - pumpStatusLayout.setVisibility(View.VISIBLE); - loopStatusLayout.setVisibility(View.GONE); - } else { - pumpStatusLayout.setVisibility(View.GONE); - loopStatusLayout.setVisibility(View.VISIBLE); - } - } - - private void processInsulinCarbsButtonsVisibility() { - BgReading lastBG = iobCobCalculatorPlugin.lastBg(); - - final PumpInterface pump = activePlugin.getActivePump(); - - final Profile profile = profileFunction.getProfile(); - final String profileName = profileFunction.getProfileName(); - - // QuickWizard button - QuickWizardEntry quickWizardEntry = quickWizard.getActive(); - if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized() && !pump.isSuspended()) { - quickWizardButton.setVisibility(View.VISIBLE); - String text = quickWizardEntry.buttonText() + "\n" + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g"; - BolusWizard wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false); - text += " " + DecimalFormatter.toPumpSupportedBolus(wizard.getCalculatedTotalInsulin(), pump) + "U"; - quickWizardButton.setText(text); - if (wizard.getCalculatedTotalInsulin() <= 0) - quickWizardButton.setVisibility(View.GONE); - } else - quickWizardButton.setVisibility(View.GONE); - - // **** Various treatment buttons **** - if (carbsButton != null) { - if ((!activePlugin.getActivePump().getPumpDescription().storesCarbInfo || (pump.isInitialized() && !pump.isSuspended())) && - profile != null && - sp.getBoolean(R.string.key_show_carbs_button, true)) - carbsButton.setVisibility(View.VISIBLE); - else - carbsButton.setVisibility(View.GONE); - } - - if (treatmentButton != null) { - if (pump.isInitialized() && !pump.isSuspended() && - profile != null && - sp.getBoolean(R.string.key_show_treatment_button, false)) - treatmentButton.setVisibility(View.VISIBLE); - else - treatmentButton.setVisibility(View.GONE); - } - if (wizardButton != null) { - if (pump.isInitialized() && !pump.isSuspended() && - profile != null && - sp.getBoolean(R.string.key_show_wizard_button, true)) - wizardButton.setVisibility(View.VISIBLE); - else - wizardButton.setVisibility(View.GONE); - } - if (insulinButton != null) { - if (pump.isInitialized() && !pump.isSuspended() && - profile != null && - sp.getBoolean(R.string.key_show_insulin_button, true)) - insulinButton.setVisibility(View.VISIBLE); - else - insulinButton.setVisibility(View.GONE); - } - } - - private void scheduleUpdateGUI(final String from) { - class UpdateRunnable implements Runnable { - public void run() { - Activity activity = getActivity(); - if (activity != null) - activity.runOnUiThread(() -> { - updateGUI(from); - scheduledUpdate = null; - }); - } - } - // prepare task for execution in 400 msec - // cancel waiting task to prevent multiple updates - if (scheduledUpdate != null) - scheduledUpdate.cancel(false); - Runnable task = new UpdateRunnable(); - final int msec = 500; - scheduledUpdate = worker.schedule(task, msec, TimeUnit.MILLISECONDS); - } - - @SuppressLint("SetTextI18n") - public void updateGUI(final String from) { - aapsLogger.debug(LTag.OVERVIEW, "updateGUI entered from: " + from); - final long updateGUIStart = System.currentTimeMillis(); - - if (getActivity() == null) - return; - - if (timeView != null) { //must not exists - timeView.setText(DateUtil.timeString(new Date())); - } - - notificationStore.updateNotifications(notificationsView); - - pumpStatusLayout.setVisibility(View.GONE); - loopStatusLayout.setVisibility(View.GONE); - - if (!profileFunction.isProfileValid("Overview")) { - pumpStatusView.setText(R.string.noprofileset); - pumpStatusLayout.setVisibility(View.VISIBLE); - return; - } - loopStatusLayout.setVisibility(View.VISIBLE); - - statusLightHandler.updateAge(sage, iage, cage, pbage); - BgReading actualBG = iobCobCalculatorPlugin.actualBg(); - BgReading lastBG = iobCobCalculatorPlugin.lastBg(); - - final PumpInterface pump = activePlugin.getActivePump(); - - final Profile profile = profileFunction.getProfile(); - if (profile == null) return; - - final String units = profileFunction.getUnits(); - final double lowLine = defaultValueHelper.determineLowLine(); - final double highLine = defaultValueHelper.determineHighLine(); - - //Start with updating the BG as it is unaffected by loop. - // **** BG value **** - if (lastBG != null) { - int color = resourceHelper.gc(R.color.inrange); - if (lastBG.valueToUnits(units) < lowLine) - color = resourceHelper.gc(R.color.low); - else if (lastBG.valueToUnits(units) > highLine) - color = resourceHelper.gc(R.color.high); - bgView.setText(lastBG.valueToUnitsToString(units)); - arrowView.setText(lastBG.directionToSymbol()); - bgView.setTextColor(color); - arrowView.setTextColor(color); - GlucoseStatus glucoseStatus = new GlucoseStatus(injector).getGlucoseStatusData(); - if (glucoseStatus != null) { - if (deltaView != null) - deltaView.setText("Δ " + Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + " " + units); - if (deltaShortView != null) - deltaShortView.setText(Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)); - if (avgdeltaView != null) - avgdeltaView.setText("øΔ15m: " + Profile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units) + "\n" + - "øΔ40m: " + Profile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)); - } else { - if (deltaView != null) - deltaView.setText("Δ " + resourceHelper.gs(R.string.notavailable)); - if (deltaShortView != null) - deltaShortView.setText("---"); - if (avgdeltaView != null) - avgdeltaView.setText(""); - } - } - - Constraint closedLoopEnabled = constraintChecker.isClosedLoopAllowed(); - - // open loop mode - if (Config.APS && pump.getPumpDescription().isTempBasalCapable) { - apsModeView.setVisibility(View.VISIBLE); - apsModeView.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault)); - apsModeView.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault)); - if (loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuperBolus()) { - apsModeView.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)); - apsModeView.setText(String.format(resourceHelper.gs(R.string.loopsuperbolusfor), loopPlugin.minutesToEndOfSuspend())); - apsModeView.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)); - } else if (loopPlugin.isDisconnected()) { - apsModeView.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical)); - apsModeView.setText(String.format(resourceHelper.gs(R.string.loopdisconnectedfor), loopPlugin.minutesToEndOfSuspend())); - apsModeView.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical)); - } else if (loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuspended()) { - apsModeView.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)); - apsModeView.setText(String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend())); - apsModeView.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)); - } else if (pump.isSuspended()) { - apsModeView.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)); - apsModeView.setText(resourceHelper.gs(R.string.pumpsuspended)); - apsModeView.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)); - } else if (loopPlugin.isEnabled(PluginType.LOOP)) { - if (closedLoopEnabled.value()) { - apsModeView.setText(resourceHelper.gs(R.string.closedloop)); - } else { - apsModeView.setText(resourceHelper.gs(R.string.openloop)); - } - } else { - apsModeView.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical)); - apsModeView.setText(resourceHelper.gs(R.string.disabledloop)); - apsModeView.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical)); - } - } else { - apsModeView.setVisibility(View.GONE); - } - - // temp target - TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(); - if (tempTarget != null) { - tempTargetView.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)); - tempTargetView.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)); - tempTargetView.setText(Profile.toTargetRangeString(tempTarget.low, tempTarget.high, Constants.MGDL, units) + " " + DateUtil.untilString(tempTarget.end(), resourceHelper)); - } else { - tempTargetView.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault)); - tempTargetView.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault)); - tempTargetView.setText(Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), Constants.MGDL, units)); - } - - // **** Temp button **** - if (acceptTempButton != null) { - boolean showAcceptButton = !closedLoopEnabled.value(); // Open mode needed - showAcceptButton = showAcceptButton && loopPlugin.lastRun != null && loopPlugin.lastRun.lastAPSRun != null; // aps result must exist - showAcceptButton = showAcceptButton && (loopPlugin.lastRun.lastOpenModeAccept == 0 || loopPlugin.lastRun.lastOpenModeAccept < loopPlugin.lastRun.lastAPSRun.getTime()); // never accepted or before last result - showAcceptButton = showAcceptButton && loopPlugin.lastRun.constraintsProcessed.isChangeRequested(); // change is requested - - if (showAcceptButton && pump.isInitialized() && !pump.isSuspended() && loopPlugin.isEnabled(PluginType.LOOP)) { - acceptTempButton.setVisibility(View.VISIBLE); - acceptTempButton.setText(resourceHelper.gs(R.string.setbasalquestion) + "\n" + loopPlugin.lastRun.constraintsProcessed); - } else { - acceptTempButton.setVisibility(View.GONE); - } - } - - // **** Calibration & CGM buttons **** - boolean xDripIsBgSource = xdripPlugin.isEnabled(PluginType.BGSOURCE); - boolean dexcomIsSource = dexcomPlugin.isEnabled(PluginType.BGSOURCE); - if (calibrationButton != null) { - if ((xDripIsBgSource || dexcomIsSource) && actualBG != null && sp.getBoolean(R.string.key_show_calibration_button, true)) { - calibrationButton.setVisibility(View.VISIBLE); - } else { - calibrationButton.setVisibility(View.GONE); - } - } - if (cgmButton != null) { - if (xDripIsBgSource && sp.getBoolean(R.string.key_show_cgm_button, false)) { - cgmButton.setVisibility(View.VISIBLE); - } else if (dexcomIsSource && sp.getBoolean(R.string.key_show_cgm_button, false)) { - cgmButton.setVisibility(View.VISIBLE); - } else { - cgmButton.setVisibility(View.GONE); - } - } - - final TemporaryBasal activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()); - String basalText = ""; - if (shorttextmode) { - if (activeTemp != null) { - basalText = "T: " + activeTemp.toStringVeryShort(); - } else { - basalText = resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal()); - } - } else { - if (activeTemp != null) { - basalText = activeTemp.toStringFull(); - } else { - basalText = resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal()); - } - } - baseBasalView.setText(basalText); - baseBasalView.setOnClickListener(v -> { - String fullText = resourceHelper.gs(R.string.pump_basebasalrate_label) + ": " + resourceHelper.gs(R.string.pump_basebasalrate, profile.getBasal()) + "\n"; - if (activeTemp != null) { - fullText += resourceHelper.gs(R.string.pump_tempbasal_label) + ": " + activeTemp.toStringFull(); - } - OKDialog.show(getActivity(), resourceHelper.gs(R.string.basal), fullText); - }); - - if (activeTemp != null) { - baseBasalView.setTextColor(resourceHelper.gc(R.color.basal)); - } else { - baseBasalView.setTextColor(resourceHelper.gc(R.color.defaulttextcolor)); - } - - - final ExtendedBolus extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis()); - String extendedBolusText = ""; - if (extendedBolusView != null) { // must not exists in all layouts - if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses()) - extendedBolusText = shorttextmode ? DecimalFormatter.to2Decimal(extendedBolus.absoluteRate()) + "U/h" : extendedBolus.toStringMedium(); - extendedBolusView.setText(extendedBolusText); - extendedBolusView.setOnClickListener(v -> { - if (extendedBolus != null) - OKDialog.show(getActivity(), resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString()); - }); - } - - activeProfileView.setText(profileFunction.getProfileNameWithDuration()); - if (profile.getPercentage() != 100 || profile.getTimeshift() != 0) { - activeProfileView.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)); - activeProfileView.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)); - } else { - activeProfileView.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault)); - activeProfileView.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault)); - } - - processInsulinCarbsButtonsVisibility(); - - // **** BG value **** - if (lastBG == null) { //left this here as it seems you want to exit at this point if it is null... - return; - } - int flag = bgView.getPaintFlags(); - if (actualBG == null) { - flag |= Paint.STRIKE_THRU_TEXT_FLAG; - } else - flag &= ~Paint.STRIKE_THRU_TEXT_FLAG; - bgView.setPaintFlags(flag); - - if (timeAgoView != null) - timeAgoView.setText(DateUtil.minAgo(resourceHelper, lastBG.date)); - if (timeAgoShortView != null) - timeAgoShortView.setText("(" + DateUtil.minAgoShort(lastBG.date) + ")"); - - // iob - treatmentsPlugin.updateTotalIOBTreatments(); - treatmentsPlugin.updateTotalIOBTempBasals(); - final IobTotal bolusIob = treatmentsPlugin.getLastCalculationTreatments().round(); - final IobTotal basalIob = treatmentsPlugin.getLastCalculationTempBasals().round(); - - if (shorttextmode) { - String iobtext = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U"; - iobView.setText(iobtext); - iobView.setOnClickListener(v -> { - String iobtext1 = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U\n" - + resourceHelper.gs(R.string.bolus) + ": " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U\n" - + resourceHelper.gs(R.string.basal) + ": " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U\n"; - OKDialog.show(getActivity(), resourceHelper.gs(R.string.iob), iobtext1); - }); - } else if (resourceHelper.gb(R.bool.isTablet)) { - String iobtext = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U (" - + resourceHelper.gs(R.string.bolus) + ": " + DecimalFormatter.to2Decimal(bolusIob.iob) + "U " - + resourceHelper.gs(R.string.basal) + ": " + DecimalFormatter.to2Decimal(basalIob.basaliob) + "U)"; - iobView.setText(iobtext); - } else { - String iobtext = DecimalFormatter.to2Decimal(bolusIob.iob + basalIob.basaliob) + "U (" - + DecimalFormatter.to2Decimal(bolusIob.iob) + "/" - + DecimalFormatter.to2Decimal(basalIob.basaliob) + ")"; - iobView.setText(iobtext); - } - - // cob - if (cobView != null) { // view must not exists - String cobText = resourceHelper.gs(R.string.value_unavailable_short); - CobInfo cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Overview COB"); - if (cobInfo.displayCob != null) { - cobText = DecimalFormatter.to0Decimal(cobInfo.displayCob); - if (cobInfo.futureCarbs > 0) - cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")"; - } - cobView.setText(cobText); - } - - if (statuslightsLayout != null) - if (sp.getBoolean(R.string.key_show_statuslights, false)) { - if (sp.getBoolean(R.string.key_show_statuslights_extended, false)) { - statusLightHandler.extendedStatusLight(cageView, iageView, reservoirView, sageView, batteryView); - statuslightsLayout.setVisibility(View.VISIBLE); - } else { - statusLightHandler.statusLight(cageView, iageView, reservoirView, sageView, batteryView); - statuslightsLayout.setVisibility(View.VISIBLE); - } - } else { - statuslightsLayout.setVisibility(View.GONE); - } - - boolean predictionsAvailable; - if (Config.APS) - predictionsAvailable = loopPlugin.lastRun != null && loopPlugin.lastRun.request.hasPredictions; - else if (Config.NSCLIENT) - predictionsAvailable = true; - else - predictionsAvailable = false; - final boolean finalPredictionsAvailable = predictionsAvailable; - - // pump status from ns - if (pumpDeviceStatusView != null) { - pumpDeviceStatusView.setText(nsDeviceStatus.getPumpStatus()); - pumpDeviceStatusView.setOnClickListener(v -> OKDialog.show(getActivity(), resourceHelper.gs(R.string.pump), nsDeviceStatus.getExtendedPumpStatus())); - } - - // OpenAPS status from ns - if (openapsDeviceStatusView != null) { - openapsDeviceStatusView.setText(nsDeviceStatus.getOpenApsStatus()); - openapsDeviceStatusView.setOnClickListener(v -> OKDialog.show(getActivity(), resourceHelper.gs(R.string.openaps), nsDeviceStatus.getExtendedOpenApsStatus())); - } - - // Uploader status from ns - if (uploaderDeviceStatusView != null) { - uploaderDeviceStatusView.setText(nsDeviceStatus.getUploaderStatusSpanned()); - uploaderDeviceStatusView.setOnClickListener(v -> OKDialog.show(getActivity(), resourceHelper.gs(R.string.uploader), nsDeviceStatus.getExtendedUploaderStatus())); - } - - // Sensitivity - if (sensitivityView != null) { - AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensData("Overview"); - if (autosensData != null) - sensitivityView.setText(String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100)); - else - sensitivityView.setText(""); - } - - // ****** GRAPH ******* - - new Thread(() -> { - // allign to hours - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(System.currentTimeMillis()); - calendar.set(Calendar.MILLISECOND, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.add(Calendar.HOUR, 1); - - int hoursToFetch; - final long toTime; - final long fromTime; - final long endTime; - - APSResult apsResult = null; - - if (finalPredictionsAvailable && sp.getBoolean("showprediction", false)) { - if (Config.APS) - apsResult = loopPlugin.lastRun.constraintsProcessed; - else - apsResult = NSDeviceStatus.getAPSResult(injector); - int predHours = (int) (Math.ceil(apsResult.getLatestPredictionsTime() - System.currentTimeMillis()) / (60 * 60 * 1000)); - predHours = Math.min(2, predHours); - predHours = Math.max(0, predHours); - hoursToFetch = rangeToDisplay - predHours; - toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding - Graphview specific - fromTime = toTime - T.hours(hoursToFetch).msecs(); - endTime = toTime + T.hours(predHours).msecs(); - } else { - hoursToFetch = rangeToDisplay; - toTime = calendar.getTimeInMillis() + 100000; // little bit more to avoid wrong rounding - Graphview specific - fromTime = toTime - T.hours(hoursToFetch).msecs(); - endTime = toTime; - } - - - final long now = System.currentTimeMillis(); - - // ------------------ 1st graph - Profiler.log(aapsLogger, LTag.OVERVIEW, from + " - 1st graph - START", updateGUIStart); - - final GraphData graphData = new GraphData(injector, bgGraph, iobCobCalculatorPlugin); - - // **** In range Area **** - graphData.addInRangeArea(fromTime, endTime, lowLine, highLine); - - // **** BG **** - if (finalPredictionsAvailable && sp.getBoolean("showprediction", false)) - graphData.addBgReadings(fromTime, toTime, lowLine, highLine, - apsResult.getPredictions()); - else - graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null); - - // set manual x bounds to have nice steps - graphData.formatAxis(fromTime, endTime); - - // Treatments - graphData.addTreatments(fromTime, endTime); - - if (sp.getBoolean("showactivityprimary", true)) { - graphData.addActivity(fromTime, endTime, false, 0.8d); - } - - // add basal data - if (pump.getPumpDescription().isTempBasalCapable && sp.getBoolean("showbasals", true)) { - graphData.addBasals(fromTime, now, lowLine / graphData.getMaxY() / 1.2d); - } - - // add target line - graphData.addTargetLine(fromTime, toTime, profile, loopPlugin.lastRun); - - // **** NOW line **** - graphData.addNowLine(now); - - // ------------------ 2nd graph - Profiler.log(aapsLogger, LTag.OVERVIEW, from + " - 2nd graph - START", updateGUIStart); - - final GraphData secondGraphData = new GraphData(injector, iobGraph, iobCobCalculatorPlugin); - - boolean useIobForScale = false; - boolean useCobForScale = false; - boolean useDevForScale = false; - boolean useRatioForScale = false; - boolean useDSForScale = false; - boolean useIAForScale = false; - - if (sp.getBoolean("showiob", true)) { - useIobForScale = true; - } else if (sp.getBoolean("showcob", true)) { - useCobForScale = true; - } else if (sp.getBoolean("showdeviations", false)) { - useDevForScale = true; - } else if (sp.getBoolean("showratios", false)) { - useRatioForScale = true; - } else if (sp.getBoolean("showactivitysecondary", false)) { - useIAForScale = true; - } else if (sp.getBoolean("showdevslope", false)) { - useDSForScale = true; - } - - if (sp.getBoolean("showiob", true)) - secondGraphData.addIob(fromTime, now, useIobForScale, 1d, sp.getBoolean("showprediction", false)); - if (sp.getBoolean("showcob", true)) - secondGraphData.addCob(fromTime, now, useCobForScale, useCobForScale ? 1d : 0.5d); - if (sp.getBoolean("showdeviations", false)) - secondGraphData.addDeviations(fromTime, now, useDevForScale, 1d); - if (sp.getBoolean("showratios", false)) - secondGraphData.addRatio(fromTime, now, useRatioForScale, 1d); - if (sp.getBoolean("showactivitysecondary", true)) - secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8d); - if (sp.getBoolean("showdevslope", false) && buildHelper.isDev()) - secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1d); - - // **** NOW line **** - // set manual x bounds to have nice steps - secondGraphData.formatAxis(fromTime, endTime); - secondGraphData.addNowLine(now); - - // do GUI update - FragmentActivity activity = getActivity(); - if (activity != null) { - activity.runOnUiThread(() -> { - if (sp.getBoolean("showiob", true) - || sp.getBoolean("showcob", true) - || sp.getBoolean("showdeviations", false) - || sp.getBoolean("showratios", false) - || sp.getBoolean("showactivitysecondary", false) - || sp.getBoolean("showdevslope", false)) { - iobGraph.setVisibility(View.VISIBLE); - } else { - iobGraph.setVisibility(View.GONE); - } - // finally enforce drawing of graphs - graphData.performUpdate(); - secondGraphData.performUpdate(); - Profiler.log(aapsLogger, LTag.OVERVIEW, from + " - onDataChanged", updateGUIStart); - }); - } - }).start(); - - Profiler.log(aapsLogger, LTag.OVERVIEW, from, updateGUIStart); - } - - -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt new file mode 100644 index 0000000000..8a0a6ee04b --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -0,0 +1,825 @@ +package info.nightscout.androidaps.plugins.general.overview + +import android.annotation.SuppressLint +import android.app.NotificationManager +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.graphics.Paint +import android.os.Bundle +import android.os.Handler +import android.util.DisplayMetrics +import android.util.TypedValue +import android.view.ContextMenu +import android.view.ContextMenu.ContextMenuInfo +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.View.OnLongClickListener +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import dagger.android.HasAndroidInjector +import dagger.android.support.DaggerFragment +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.dialogs.CalibrationDialog +import info.nightscout.androidaps.dialogs.CarbsDialog +import info.nightscout.androidaps.dialogs.InsulinDialog +import info.nightscout.androidaps.dialogs.TreatmentDialog +import info.nightscout.androidaps.dialogs.WizardDialog +import info.nightscout.androidaps.events.* +import info.nightscout.androidaps.interfaces.ActivePluginProvider +import info.nightscout.androidaps.interfaces.Constraint +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.loop.events.EventNewOpenLoopNotification +import info.nightscout.androidaps.plugins.bus.RxBusWrapper +import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin +import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker +import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction +import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus +import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity +import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData +import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore +import info.nightscout.androidaps.plugins.general.wear.ActionStringHandler +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished +import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress +import info.nightscout.androidaps.plugins.source.DexcomPlugin +import info.nightscout.androidaps.plugins.source.XdripPlugin +import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin +import info.nightscout.androidaps.queue.CommandQueue +import info.nightscout.androidaps.utils.* +import info.nightscout.androidaps.utils.buildHelper.BuildHelper +import info.nightscout.androidaps.utils.protection.ProtectionCheck +import info.nightscout.androidaps.utils.resources.ResourceHelper +import info.nightscout.androidaps.utils.sharedPreferences.SP +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.careportal_stats_fragment.* +import kotlinx.android.synthetic.main.overview_fragment.* +import kotlinx.android.synthetic.main.overview_fragment.overview_activeprofile +import kotlinx.android.synthetic.main.overview_fragment.overview_apsmode +import kotlinx.android.synthetic.main.overview_fragment.overview_arrow +import kotlinx.android.synthetic.main.overview_fragment.overview_basebasal +import kotlinx.android.synthetic.main.overview_fragment.overview_bg +import kotlinx.android.synthetic.main.overview_fragment.overview_bggraph +import kotlinx.android.synthetic.main.overview_fragment.overview_carbsbutton +import kotlinx.android.synthetic.main.overview_fragment.overview_chartMenuButton +import kotlinx.android.synthetic.main.overview_fragment.overview_cob +import kotlinx.android.synthetic.main.overview_fragment.overview_extendedbolus +import kotlinx.android.synthetic.main.overview_fragment.overview_insulinbutton +import kotlinx.android.synthetic.main.overview_fragment.overview_iob +import kotlinx.android.synthetic.main.overview_fragment.overview_iobcalculationprogess +import kotlinx.android.synthetic.main.overview_fragment.overview_iobgraph +import kotlinx.android.synthetic.main.overview_fragment.overview_looplayout +import kotlinx.android.synthetic.main.overview_fragment.overview_notifications +import kotlinx.android.synthetic.main.overview_fragment.overview_pumpstatus +import kotlinx.android.synthetic.main.overview_fragment.overview_pumpstatuslayout +import kotlinx.android.synthetic.main.overview_fragment.overview_quickwizardbutton +import kotlinx.android.synthetic.main.overview_fragment.overview_sensitivity +import kotlinx.android.synthetic.main.overview_fragment.overview_temptarget +import kotlinx.android.synthetic.main.overview_fragment.overview_treatmentbutton +import kotlinx.android.synthetic.main.overview_fragment.overview_wizardbutton +import kotlinx.android.synthetic.main.overview_fragment_nsclient_tablet.* +import java.util.* +import java.util.concurrent.Executors +import java.util.concurrent.ScheduledFuture +import java.util.concurrent.TimeUnit +import javax.inject.Inject +import kotlin.math.abs +import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min + +class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickListener { + @Inject lateinit var injector: HasAndroidInjector + @Inject lateinit var aapsLogger: AAPSLogger + @Inject lateinit var sp: SP + @Inject lateinit var rxBus: RxBusWrapper + @Inject lateinit var resourceHelper: ResourceHelper + @Inject lateinit var defaultValueHelper: DefaultValueHelper + @Inject lateinit var profileFunction: ProfileFunction + @Inject lateinit var constraintChecker: ConstraintChecker + @Inject lateinit var statusLightHandler: StatusLightHandler + @Inject lateinit var nsDeviceStatus: NSDeviceStatus + @Inject lateinit var loopPlugin: LoopPlugin + @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin + @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var treatmentsPlugin: TreatmentsPlugin + @Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin + @Inject lateinit var dexcomPlugin: DexcomPlugin + @Inject lateinit var xdripPlugin: XdripPlugin + @Inject lateinit var notificationStore: NotificationStore + @Inject lateinit var actionStringHandler: ActionStringHandler + @Inject lateinit var quickWizard: QuickWizard + @Inject lateinit var buildHelper: BuildHelper + @Inject lateinit var commandQueue: CommandQueue + @Inject lateinit var protectionCheck: ProtectionCheck + @Inject lateinit var fabricPrivacy: FabricPrivacy + @Inject lateinit var overviewMenus: OverviewMenus + + private val disposable = CompositeDisposable() + + private var smallWidth = false + private var smallHeight = false + private lateinit var dm: DisplayMetrics + private var rangeToDisplay = 6 // for graph + private var loopHandler = Handler() + private var refreshLoop: Runnable? = null + + private val worker = Executors.newSingleThreadScheduledExecutor() + private var scheduledUpdate: ScheduledFuture<*>? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + //check screen width + dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + + val screenWidth = dm.widthPixels + val screenHeight = dm.heightPixels + smallWidth = screenWidth <= Constants.SMALL_WIDTH + smallHeight = screenHeight <= Constants.SMALL_HEIGHT + val landscape = screenHeight < screenWidth + + return when { + resourceHelper.gb(R.bool.isTablet) && Config.NSCLIENT -> + inflater.inflate(R.layout.overview_fragment_nsclient_tablet, container, false) + + Config.NSCLIENT -> + inflater.inflate(R.layout.overview_fragment_nsclient, container, false) + + smallHeight || landscape -> + inflater.inflate(R.layout.overview_fragment_landscape, container, false) + + else -> + inflater.inflate(R.layout.overview_fragment, container, false) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + if (smallWidth) overview_arrow?.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 35f) + overview_pumpstatus?.setBackgroundColor(resourceHelper.gc(R.color.colorInitializingBorder)) + + overview_notifications?.setHasFixedSize(false) + overview_notifications?.layoutManager = LinearLayoutManager(view.context) + val 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_iobgraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) + overview_iobgraph?.gridLabelRenderer?.reloadStyles() + overview_iobgraph?.gridLabelRenderer?.isHorizontalLabelsVisible = false + overview_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth + overview_iobgraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth + overview_iobgraph?.gridLabelRenderer?.numVerticalLabels = 3 + rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6) + + overview_bggraph?.setOnLongClickListener { + rangeToDisplay += 6 + rangeToDisplay = if (rangeToDisplay > 24) 6 else rangeToDisplay + sp.putInt(R.string.key_rangetodisplay, rangeToDisplay) + updateGUI("rangeChange") + sp.putBoolean(R.string.key_objectiveusescale, true) + false + } + overviewMenus.setupChartMenu(overview_chartMenuButton) + + 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) + } + + override fun onPause() { + super.onPause() + disposable.clear() + loopHandler.removeCallbacksAndMessages(null) + overview_apsmode?.let { unregisterForContextMenu(it) } + overview_activeprofile?.let { unregisterForContextMenu(it) } + overview_temptarget?.let { unregisterForContextMenu(it) } + } + + override fun onResume() { + super.onResume() + disposable.add(rxBus + .toObservable(EventRefreshOverview::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI(it.from) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventExtendedBolusChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventExtendedBolusChange") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventTempBasalChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventTempBasalChange") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventTreatmentChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventTreatmentChange") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventTempTargetChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventTempTargetChange") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventAcceptOpenLoopChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventAcceptOpenLoopChange") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventCareportalEventChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventCareportalEventChange") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventInitializationChanged::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventInitializationChanged") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventAutosensCalculationFinished::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventAutosensCalculationFinished") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventProfileNeedsUpdate::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventProfileNeedsUpdate") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventPreferenceChange::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventPreferenceChange") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventNewOpenLoopNotification::class.java) + .observeOn(Schedulers.io()) + .subscribe({ scheduleUpdateGUI("EventNewOpenLoopNotification") }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventPumpStatusChanged::class.java) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ updatePumpStatus(it) }) { fabricPrivacy.logException(it) }) + disposable.add(rxBus + .toObservable(EventIobCalculationProgress::class.java) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ overview_iobcalculationprogess?.text = it.progress }) { fabricPrivacy.logException(it) }) + + refreshLoop = Runnable { + scheduleUpdateGUI("refreshLoop") + loopHandler.postDelayed(refreshLoop, 60 * 1000L) + } + loopHandler.postDelayed(refreshLoop, 60 * 1000L) + + overview_apsmode?.let { registerForContextMenu(overview_apsmode) } + overview_activeprofile?.let { registerForContextMenu(it) } + overview_temptarget?.let { registerForContextMenu(it) } + updateGUI("onResume") + } + + override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo?) { + super.onCreateContextMenu(menu, v, menuInfo) + overviewMenus.createContextMenu(menu, v) + } + + override fun onContextItemSelected(item: MenuItem): Boolean { + val manager = fragmentManager + return if (manager != null && overviewMenus.onContextItemSelected(item, manager)) true else super.onContextItemSelected(item) + } + + override fun onClick(v: View) { + val manager = fragmentManager ?: return + // 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 (manager.isStateSaved) return + activity?.let { activity -> + when (v.id) { + R.id.overview_treatmentbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { TreatmentDialog().show(manager, "Overview") }) + R.id.overview_wizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { WizardDialog().show(manager, "Overview") }) + R.id.overview_insulinbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { InsulinDialog().show(manager, "Overview") }) + R.id.overview_quickwizardbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { onClickQuickWizard() }) + R.id.overview_carbsbutton -> protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { CarbsDialog().show(manager, "Overview") }) + + R.id.overview_pumpstatus -> { + if (activePlugin.activePump.isSuspended || !activePlugin.activePump.isInitialized) commandQueue.readStatus("RefreshClicked", null) + } + + R.id.overview_cgmbutton -> { + if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) + openCgmApp("com.eveningoutpost.dexdrip") + else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) { + dexcomPlugin.findDexcomPackageName()?.let { + openCgmApp(it) + } + ?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed)) + } + } + + R.id.overview_calibrationbutton -> { + if (xdripPlugin.isEnabled(PluginType.BGSOURCE)) { + CalibrationDialog().show(manager, "CalibrationDialog") + } else if (dexcomPlugin.isEnabled(PluginType.BGSOURCE)) { + try { + dexcomPlugin.findDexcomPackageName()?.let { + startActivity(Intent("com.dexcom.cgm.activities.MeterEntryActivity").setPackage(it)) + } + ?: ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.dexcom_app_not_installed)) + } catch (e: ActivityNotFoundException) { + ToastUtils.showToastInUiThread(activity, resourceHelper.gs(R.string.g5appnotdetected)) + } + } + } + + R.id.overview_accepttempbutton -> { + profileFunction.getProfile() ?: return + if (loopPlugin.isEnabled(PluginType.LOOP)) { + val lastRun = loopPlugin.lastRun + loopPlugin.invoke("Accept temp button", false) + if (lastRun?.lastAPSRun != null && lastRun.constraintsProcessed.isChangeRequested) { + OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.pump_tempbasal_label), lastRun.constraintsProcessed.toSpanned(), Runnable { + aapsLogger.debug("USER ENTRY: ACCEPT TEMP BASAL") + overview_accepttempbutton?.visibility = View.GONE + (context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancel(Constants.notificationID) + actionStringHandler.handleInitiate("cancelChangeRequest") + loopPlugin.acceptChangeRequest() + }) + } + } + } + } + } + } + + private fun openCgmApp(packageName: String) { + context?.let { + val packageManager = it.packageManager + try { + val intent = packageManager.getLaunchIntentForPackage(packageName) + ?: throw ActivityNotFoundException() + intent.addCategory(Intent.CATEGORY_LAUNCHER) + it.startActivity(intent) + } catch (e: ActivityNotFoundException) { + OKDialog.show(it, "", resourceHelper.gs(R.string.error_starting_cgm)) + } + } + } + + override fun onLongClick(v: View): Boolean { + when (v.id) { + R.id.overview_quickwizardbutton -> { + startActivity(Intent(v.context, QuickWizardListActivity::class.java)) + return true + } + } + return false + } + + private fun onClickQuickWizard() { + val actualBg = iobCobCalculatorPlugin.actualBg() + val profile = profileFunction.getProfile() + val profileName = profileFunction.getProfileName() + val pump = activePlugin.activePump + val quickWizardEntry = quickWizard.getActive() + if (quickWizardEntry != null && actualBg != null && profile != null) { + overview_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() + activity?.let { + if (abs(wizard.insulinAfterConstraints - wizard.calculatedTotalInsulin) >= pump.pumpDescription.pumpType.determineCorrectBolusStepSize(wizard.insulinAfterConstraints) || carbsAfterConstraints != quickWizardEntry.carbs()) { + OKDialog.show(it, resourceHelper.gs(R.string.treatmentdeliveryerror), resourceHelper.gs(R.string.constraints_violation) + "\n" + resourceHelper.gs(R.string.changeyourinput)) + return + } + wizard.confirmAndExecute(it) + } + } + } + } + + 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 + } else { + overview_pumpstatuslayout?.visibility = View.GONE + overview_looplayout?.visibility = View.VISIBLE + } + } + + @SuppressLint("SetTextI18n") + private fun processButtonsVisibility() { + val lastBG = iobCobCalculatorPlugin.lastBg() + val pump = activePlugin.activePump + val profile = profileFunction.getProfile() + val profileName = profileFunction.getProfileName() + val actualBG = iobCobCalculatorPlugin.actualBg() + + // QuickWizard button + val quickWizardEntry = quickWizard.getActive() + if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized && !pump.isSuspended) { + overview_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()) + + " " + resourceHelper.gs(R.string.formatinsulinunits, wizard.calculatedTotalInsulin) + if (wizard.calculatedTotalInsulin <= 0) overview_quickwizardbutton?.visibility = View.GONE + } else overview_quickwizardbutton?.visibility = View.GONE + + // **** Temp button **** + val lastRun = loopPlugin.lastRun + val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() + + val showAcceptButton = !closedLoopEnabled.value() && // Open mode needed + lastRun != null && + (lastRun.lastOpenModeAccept == 0L || lastRun.lastOpenModeAccept < lastRun.lastAPSRun) &&// never accepted or before last result + lastRun.constraintsProcessed.isChangeRequested // 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}" + } else { + overview_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() + + // **** 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() + + } + + private fun scheduleUpdateGUI(from: String) { + class UpdateRunnable : Runnable { + override fun run() { + activity?.runOnUiThread { + updateGUI(from) + scheduledUpdate = null + } + } + } + // prepare task for execution in 500 milliseconds + // cancel waiting task to prevent multiple updates + scheduledUpdate?.cancel(false) + val task: Runnable = UpdateRunnable() + scheduledUpdate = worker.schedule(task, 500, TimeUnit.MILLISECONDS) + } + + @SuppressLint("SetTextI18n") + fun updateGUI(from: String) { + aapsLogger.debug("UpdateGUI from $from") + + overview_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 + return + } + notificationStore.updateNotifications(overview_notifications) + overview_pumpstatuslayout?.visibility = View.GONE + overview_looplayout?.visibility = View.VISIBLE + + val profile = profileFunction.getProfile() ?: return + val actualBG = iobCobCalculatorPlugin.actualBg() + val lastBG = iobCobCalculatorPlugin.lastBg() + val pump = activePlugin.activePump + val units = profileFunction.getUnits() + val lowLine = defaultValueHelper.determineLowLine() + val highLine = defaultValueHelper.determineHighLine() + + //Start with updating the BG as it is unaffected by loop. + // **** BG value **** + if (lastBG != null) { + val color = when { + lastBG.valueToUnits(units) < lowLine -> resourceHelper.gc(R.color.low) + lastBG.valueToUnits(units) > highLine -> resourceHelper.gc(R.color.high) + else -> resourceHelper.gc(R.color.inrange) + } + + overview_bg?.text = lastBG.valueToUnitsToString(units) + overview_bg?.setTextColor(color) + overview_arrow?.text = lastBG.directionToSymbol() + overview_arrow?.setTextColor(color) + + val glucoseStatus = GlucoseStatus(injector).glucoseStatusData + if (glucoseStatus != null) { + overview_delta?.text = "Δ ${Profile.toUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)} $units" + overview_deltashort?.text = Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units) + overview_avgdelta?.text = "øΔ15m: ${Profile.toUnitsString(glucoseStatus.short_avgdelta, glucoseStatus.short_avgdelta * Constants.MGDL_TO_MMOLL, units)}\nøΔ40m: ${Profile.toUnitsString(glucoseStatus.long_avgdelta, glucoseStatus.long_avgdelta * Constants.MGDL_TO_MMOLL, units)}" + } else { + overview_delta?.text = "Δ " + resourceHelper.gs(R.string.notavailable) + overview_deltashort?.text = "---" + overview_avgdelta?.text = "" + } + + // strike through if BG is old + overview_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) + ")" + + } + val closedLoopEnabled = constraintChecker.isClosedLoopAllowed() + + // open loop mode + if (Config.APS && pump.pumpDescription.isTempBasalCapable) { + overview_apsmode?.visibility = View.VISIBLE + when { + loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuperBolus -> { + overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopsuperbolusfor), loopPlugin.minutesToEndOfSuspend()) + overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)) + overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)) + } + + loopPlugin.isDisconnected -> { + overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopdisconnectedfor), loopPlugin.minutesToEndOfSuspend()) + overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical)) + overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical)) + } + + loopPlugin.isEnabled(PluginType.LOOP) && loopPlugin.isSuspended -> { + overview_apsmode?.text = String.format(resourceHelper.gs(R.string.loopsuspendedfor), loopPlugin.minutesToEndOfSuspend()) + overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)) + overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)) + } + + pump.isSuspended -> { + overview_apsmode?.text = resourceHelper.gs(R.string.pumpsuspended) + overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonWarning)) + overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextWarning)) + } + + loopPlugin.isEnabled(PluginType.LOOP) -> { + overview_apsmode?.text = if (closedLoopEnabled.value()) resourceHelper.gs(R.string.closedloop) else resourceHelper.gs(R.string.openloop) + overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault)) + overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault)) + } + + else -> { + overview_apsmode?.text = resourceHelper.gs(R.string.disabledloop) + overview_apsmode?.setBackgroundColor(resourceHelper.gc(R.color.ribbonCritical)) + overview_apsmode?.setTextColor(resourceHelper.gc(R.color.ribbonTextCritical)) + } + } + } else { + overview_apsmode?.visibility = View.GONE + } + + // 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) + } 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) + } + + // Basal, TBR + val activeTemp = treatmentsPlugin.getTempBasalFromHistory(System.currentTimeMillis()) + overview_basebasal?.text = activeTemp?.let { if (resourceHelper.shortTextMode()) "T: " + activeTemp.toStringVeryShort() else activeTemp.toStringFull() } + ?: resourceHelper.gs(R.string.pump_basebasalrate, profile.basal) + overview_basebasal?.setOnClickListener { + var fullText = "${resourceHelper.gs(R.string.pump_basebasalrate_label)}: ${resourceHelper.gs(R.string.pump_basebasalrate, profile.basal)}" + if (activeTemp != null) + fullText += "\n" + resourceHelper.gs(R.string.pump_tempbasal_label) + ": " + activeTemp.toStringFull() + activity?.let { + OKDialog.show(it, resourceHelper.gs(R.string.basal), fullText) + } + } + overview_basebasal?.setTextColor(activeTemp?.let { resourceHelper.gc(R.color.basal) } + ?: resourceHelper.gc(R.color.defaulttextcolor)) + + // Extended bolus + val extendedBolus = treatmentsPlugin.getExtendedBolusFromHistory(System.currentTimeMillis()) + overview_extendedbolus?.text = if (extendedBolus != null && !pump.isFakingTempsByExtendedBoluses) { + if (resourceHelper.shortTextMode()) resourceHelper.gs(R.string.pump_basebasalrate, extendedBolus.absoluteRate()) + else extendedBolus.toStringMedium() + } else "" + overview_extendedbolus?.setOnClickListener { + if (extendedBolus != null) activity?.let { + OKDialog.show(it, resourceHelper.gs(R.string.extended_bolus), extendedBolus.toString()) + } + } + + overview_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)) + } else { + overview_activeprofile?.setBackgroundColor(resourceHelper.gc(R.color.ribbonDefault)) + overview_activeprofile?.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault)) + } + + processButtonsVisibility() + + // iob + treatmentsPlugin.updateTotalIOBTreatments() + treatmentsPlugin.updateTotalIOBTempBasals() + val bolusIob = treatmentsPlugin.lastCalculationTreatments.round() + val basalIob = treatmentsPlugin.lastCalculationTempBasals.round() + overview_iob?.text = when { + resourceHelper.shortTextMode() -> { + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + } + + resourceHelper.gb(R.bool.isTablet) -> { + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + " (" + + resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + + resourceHelper.gs(R.string.basal) + ": " + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ")" + } + + else -> { + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + " (" + + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "/" + + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ")" + } + } + overview_iob?.setOnClickListener { + activity?.let { + OKDialog.show(it, resourceHelper.gs(R.string.iob), + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob + basalIob.basaliob) + "\n" + + resourceHelper.gs(R.string.bolus) + ": " + resourceHelper.gs(R.string.formatinsulinunits, bolusIob.iob) + "\n" + + resourceHelper.gs(R.string.basal) + ": " + resourceHelper.gs(R.string.formatinsulinunits, basalIob.basaliob) + ) + } + } + + // NSClient mode + statusLightHandler.updateAge(careportal_sensorage, careportal_insulinage, careportal_canulaage, careportal_pbage) + // Mode modes + if (sp.getBoolean(R.string.key_show_statuslights, false)) { + if (sp.getBoolean(R.string.key_show_statuslights_extended, false)) + statusLightHandler.extendedStatusLight(overview_canulaage, overview_insulinage, overview_reservoirlevel, overview_sensorage, overview_batterylevel) + else + statusLightHandler.statusLight(overview_canulaage, overview_insulinage, overview_reservoirlevel, overview_sensorage, overview_batterylevel) + } + + // cob + var cobText: String = resourceHelper.gs(R.string.value_unavailable_short) + val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "Overview COB") + if (cobInfo.displayCob != null) { + cobText = DecimalFormatter.to0Decimal(cobInfo.displayCob) + if (cobInfo.futureCarbs > 0) cobText += "(" + DecimalFormatter.to0Decimal(cobInfo.futureCarbs) + ")" + } + overview_cob?.text = cobText + + val lastRun = loopPlugin.lastRun + val predictionsAvailable = if (Config.APS) lastRun?.request?.hasPredictions == true else Config.NSCLIENT + + // pump status from ns + overview_pump?.text = nsDeviceStatus.pumpStatus + overview_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) } } + + // Uploader status from ns + overview_uploader?.text = nsDeviceStatus.uploaderStatusSpanned + overview_uploader?.setOnClickListener { activity?.let { OKDialog.show(it, resourceHelper.gs(R.string.uploader), nsDeviceStatus.extendedUploaderStatus) } } + + // Sensitivity + iobCobCalculatorPlugin.getLastAutosensData("Overview")?.let { autosensData -> + overview_sensitivity?.text = String.format(Locale.ENGLISH, "%.0f%%", autosensData.autosensResult.ratio * 100) + } + + // ****** GRAPH ******* + Thread(Runnable { + + // align to hours + val calendar = Calendar.getInstance() + calendar.timeInMillis = System.currentTimeMillis() + calendar[Calendar.MILLISECOND] = 0 + calendar[Calendar.SECOND] = 0 + calendar[Calendar.MINUTE] = 0 + calendar.add(Calendar.HOUR, 1) + val hoursToFetch: Int + val toTime: Long + val fromTime: Long + val endTime: Long + val apsResult = if (Config.APS) lastRun?.constraintsProcessed else NSDeviceStatus.getAPSResult(injector) + if (predictionsAvailable && apsResult != null && sp.getBoolean("showprediction", false)) { + var predHours = (ceil(apsResult.latestPredictionsTime - System.currentTimeMillis().toDouble()) / (60 * 60 * 1000)).toInt() + predHours = min(2, predHours) + predHours = max(0, predHours) + hoursToFetch = rangeToDisplay - predHours + toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific + fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs() + endTime = toTime + T.hours(predHours.toLong()).msecs() + } else { + hoursToFetch = rangeToDisplay + toTime = calendar.timeInMillis + 100000 // little bit more to avoid wrong rounding - GraphView specific + fromTime = toTime - T.hours(hoursToFetch.toLong()).msecs() + endTime = toTime + } + val now = System.currentTimeMillis() + + // ------------------ 1st graph + val graphData = GraphData(injector, overview_bggraph, iobCobCalculatorPlugin) + + // **** In range Area **** + graphData.addInRangeArea(fromTime, endTime, lowLine, highLine) + + // **** BG **** + if (predictionsAvailable && sp.getBoolean("showprediction", false)) graphData.addBgReadings(fromTime, toTime, lowLine, highLine, + apsResult?.predictions) else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) + + // set manual x bounds to have nice steps + graphData.formatAxis(fromTime, endTime) + + // Treatments + graphData.addTreatments(fromTime, endTime) + if (sp.getBoolean("showactivityprimary", true)) + graphData.addActivity(fromTime, endTime, false, 0.8) + + // add basal data + if (pump.pumpDescription.isTempBasalCapable && sp.getBoolean("showbasals", true)) + graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2) + + // add target line + graphData.addTargetLine(fromTime, toTime, profile, loopPlugin.lastRun) + + // **** NOW line **** + graphData.addNowLine(now) + + // ------------------ 2nd graph + val secondGraphData = GraphData(injector, overview_iobgraph, iobCobCalculatorPlugin) + var useIobForScale = false + var useCobForScale = false + var useDevForScale = false + var useRatioForScale = false + var useDSForScale = false + var useIAForScale = false + // finally enforce drawing of graphs + when { + sp.getBoolean("showiob", true) -> + useIobForScale = true + sp.getBoolean("showcob", true) -> + useCobForScale = true + sp.getBoolean("showdeviations", false) -> + useDevForScale = true + sp.getBoolean("showratios", false) -> + useRatioForScale = true + sp.getBoolean("showactivitysecondary", false) -> + useIAForScale = true + sp.getBoolean("showdevslope", false) -> + useDSForScale = true + } + + if (sp.getBoolean("showiob", true)) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, sp.getBoolean("showprediction", false)) + if (sp.getBoolean("showcob", true)) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5) + if (sp.getBoolean("showdeviations", false)) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0) + if (sp.getBoolean("showratios", false)) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0) + if (sp.getBoolean("showactivitysecondary", true)) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8) + if (sp.getBoolean("showdevslope", false) && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0) + + // **** NOW line **** + // set manual x bounds to have nice steps + secondGraphData.formatAxis(fromTime, endTime) + secondGraphData.addNowLine(now) + + // do GUI update + val activity = activity + activity?.runOnUiThread { + if (sp.getBoolean("showiob", true) + || sp.getBoolean("showcob", true) + || sp.getBoolean("showdeviations", false) + || sp.getBoolean("showratios", false) + || sp.getBoolean("showactivitysecondary", false) + || sp.getBoolean("showdevslope", false)) { + overview_iobgraph?.visibility = View.VISIBLE + } else { + overview_iobgraph?.visibility = View.GONE + } + // finally enforce drawing of graphs + graphData.performUpdate() + secondGraphData.performUpdate() + } + }).start() + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt index 3336f62ab6..3e3714a89d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt @@ -31,7 +31,6 @@ import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction -import info.nightscout.androidaps.plugins.general.overview.OverviewFragment.CHARTTYPE import info.nightscout.androidaps.queue.Callback import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DefaultValueHelper @@ -58,6 +57,10 @@ class OverviewMenus @Inject constructor( private val loopPlugin: LoopPlugin ) { + enum class CharType { + PRE, BAS, IOB, COB, DEV, SEN, ACTPRIM, ACTSEC, DEVSLOPE + } + fun setupChartMenu(chartButton: ImageButton) { chartButton.setOnClickListener { v: View -> val predictionsAvailable: Boolean = when { @@ -72,7 +75,7 @@ class OverviewMenus @Inject constructor( //var s: SpannableString val popup = PopupMenu(v.context, v) if (predictionsAvailable) { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.PRE.ordinal, Menu.NONE, "Predictions") + val item = popup.menu.add(Menu.NONE, CharType.PRE.ordinal, Menu.NONE, "Predictions") val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -82,7 +85,7 @@ class OverviewMenus @Inject constructor( item.isChecked = sp.getBoolean("showprediction", true) } run { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.BAS.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_basals)) + val item = popup.menu.add(Menu.NONE, CharType.BAS.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_basals)) val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -92,7 +95,7 @@ class OverviewMenus @Inject constructor( item.isChecked = sp.getBoolean("showbasals", true) } run { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.ACTPRIM.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity)) + val item = popup.menu.add(Menu.NONE, CharType.ACTPRIM.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity)) val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -104,7 +107,7 @@ class OverviewMenus @Inject constructor( dividerItem.isEnabled = false } run { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.IOB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_iob)) + val item = popup.menu.add(Menu.NONE, CharType.IOB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_iob)) val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -114,7 +117,7 @@ class OverviewMenus @Inject constructor( item.isChecked = sp.getBoolean("showiob", true) } run { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.COB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_cob)) + val item = popup.menu.add(Menu.NONE, CharType.COB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_cob)) val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -124,7 +127,7 @@ class OverviewMenus @Inject constructor( item.isChecked = sp.getBoolean("showcob", true) } run { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.DEV.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_deviations)) + val item = popup.menu.add(Menu.NONE, CharType.DEV.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_deviations)) val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -134,7 +137,7 @@ class OverviewMenus @Inject constructor( item.isChecked = sp.getBoolean("showdeviations", false) } run { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.SEN.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_sensitivity)) + val item = popup.menu.add(Menu.NONE, CharType.SEN.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_sensitivity)) val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -144,7 +147,7 @@ class OverviewMenus @Inject constructor( item.isChecked = sp.getBoolean("showratios", false) } run { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.ACTSEC.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity)) + val item = popup.menu.add(Menu.NONE, CharType.ACTSEC.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity)) val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -154,7 +157,7 @@ class OverviewMenus @Inject constructor( item.isChecked = sp.getBoolean("showactivitysecondary", true) } if (buildHelper.isDev()) { - val item = popup.menu.add(Menu.NONE, CHARTTYPE.DEVSLOPE.ordinal, Menu.NONE, "Deviation slope") + val item = popup.menu.add(Menu.NONE, CharType.DEVSLOPE.ordinal, Menu.NONE, "Deviation slope") val title = item.title if (titleMaxChars < title.length) titleMaxChars = title.length val s = SpannableString(title) @@ -168,15 +171,15 @@ class OverviewMenus @Inject constructor( dividerItem.title = String(CharArray(titleMaxChars + 10)).replace("\u0000", "_") popup.setOnMenuItemClickListener { when (it.itemId) { - CHARTTYPE.PRE.ordinal -> sp.putBoolean("showprediction", !it.isChecked) - CHARTTYPE.BAS.ordinal -> sp.putBoolean("showbasals", !it.isChecked) - CHARTTYPE.IOB.ordinal -> sp.putBoolean("showiob", !it.isChecked) - CHARTTYPE.COB.ordinal -> sp.putBoolean("showcob", !it.isChecked) - CHARTTYPE.DEV.ordinal -> sp.putBoolean("showdeviations", !it.isChecked) - CHARTTYPE.SEN.ordinal -> sp.putBoolean("showratios", !it.isChecked) - CHARTTYPE.ACTPRIM.ordinal -> sp.putBoolean("showactivityprimary", !it.isChecked) - CHARTTYPE.ACTSEC.ordinal -> sp.putBoolean("showactivitysecondary", !it.isChecked) - CHARTTYPE.DEVSLOPE.ordinal -> sp.putBoolean("showdevslope", !it.isChecked) + CharType.PRE.ordinal -> sp.putBoolean("showprediction", !it.isChecked) + CharType.BAS.ordinal -> sp.putBoolean("showbasals", !it.isChecked) + CharType.IOB.ordinal -> sp.putBoolean("showiob", !it.isChecked) + CharType.COB.ordinal -> sp.putBoolean("showcob", !it.isChecked) + CharType.DEV.ordinal -> sp.putBoolean("showdeviations", !it.isChecked) + CharType.SEN.ordinal -> sp.putBoolean("showratios", !it.isChecked) + CharType.ACTPRIM.ordinal -> sp.putBoolean("showactivityprimary", !it.isChecked) + CharType.ACTSEC.ordinal -> sp.putBoolean("showactivitysecondary", !it.isChecked) + CharType.DEVSLOPE.ordinal -> sp.putBoolean("showdevslope", !it.isChecked) } rxBus.send(EventRefreshOverview("OnMenuItemClickListener")) return@setOnMenuItemClickListener true diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt index 6900614a96..79b1c80ba1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/StatusLightHandler.kt @@ -89,9 +89,9 @@ class StatusLightHandler @Inject constructor( /** * applies the extended statusLight subview on the overview fragment */ - fun extendedStatusLight(cageView: TextView, iAgeView: TextView, - reservoirView: TextView, sageView: TextView, - batteryView: TextView) { + fun extendedStatusLight(cageView: TextView?, iAgeView: TextView?, + reservoirView: TextView?, sageView: TextView?, + batteryView: TextView?) { val pump = activePlugin.activePump handleAge("cage", CareportalEvent.SITECHANGE, cageView, "CAN ", 48, 72) @@ -112,11 +112,11 @@ class StatusLightHandler @Inject constructor( } } - private fun handleAge(nsSettingPlugin: String, eventName: String, view: TextView, text: String, + private fun handleAge(nsSettingPlugin: String, eventName: String, view: TextView?, text: String, defaultWarnThreshold: Int, defaultUrgentThreshold: Int) { val urgent = nsSettingsStatus.getExtendedWarnValue(nsSettingPlugin, "urgent", defaultUrgentThreshold.toDouble()) val warn = nsSettingsStatus.getExtendedWarnValue(nsSettingPlugin, "warn", defaultWarnThreshold.toDouble()) - handleAge(view, text, eventName, warn, urgent, true) + handleAge(view, text, eventName, warn, urgent) } private fun handleLevel(criticalSetting: Int, criticalDefaultValue: Double, @@ -132,14 +132,14 @@ class StatusLightHandler @Inject constructor( } private fun handleAge(age: TextView?, eventType: String, warnThreshold: Double, urgentThreshold: Double) = - handleAge(age, "", eventType, warnThreshold, urgentThreshold, OverviewFragment.shorttextmode) + handleAge(age, "", eventType, warnThreshold, urgentThreshold) - fun handleAge(age: TextView?, prefix: String, eventType: String, warnThreshold: Double, urgentThreshold: Double, useShortText: Boolean) { - val notavailable = if (useShortText) "-" else resourceHelper.gs(R.string.notavailable) + fun handleAge(age: TextView?, prefix: String, eventType: String, warnThreshold: Double, urgentThreshold: Double) { + val notavailable = if (resourceHelper.shortTextMode()) "-" else resourceHelper.gs(R.string.notavailable) val careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventType) if (careportalEvent != null) { age?.setTextColor(determineTextColor(careportalEvent, warnThreshold, urgentThreshold)) - age?.text = prefix + careportalEvent.age(useShortText) + age?.text = prefix + careportalEvent.age(resourceHelper.shortTextMode()) } else { age?.text = notavailable } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt index fc7d1eb2a1..4848453d91 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/graphData/GraphData.kt @@ -61,7 +61,7 @@ class GraphData(injector: HasAndroidInjector, private val graph: GraphView, priv var maxBgValue = Double.MIN_VALUE bgReadingsArray = iobCobCalculatorPlugin.bgReadings if (bgReadingsArray?.isEmpty() != false) { - aapsLogger.debug(LTag.OVERVIEW, "No BG data.") + aapsLogger.debug("No BG data.") maxY = 10.0 minY = 0.0 return diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt index 594c2f5c5b..f1c58029d1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/ActionStringHandler.kt @@ -291,11 +291,12 @@ class ActionStringHandler @Inject constructor( } else if ("changeRequest" == act[0]) { ////////////////////////////////////////////// CHANGE REQUEST rTitle = resourceHelper.gs(R.string.openloop_newsuggestion) rAction = "changeRequest" - val finalLastRun = loopPlugin.lastRun - rMessage += finalLastRun.constraintsProcessed - wearPlugin.requestChangeConfirmation(rTitle, rMessage, rAction) - lastSentTimestamp = System.currentTimeMillis() - lastConfirmActionString = rAction + loopPlugin.lastRun?.let { + rMessage += it.constraintsProcessed + wearPlugin.requestChangeConfirmation(rTitle, rMessage, rAction) + lastSentTimestamp = System.currentTimeMillis() + lastConfirmActionString = rAction + } return } else if ("cancelChangeRequest" == act[0]) { ////////////////////////////////////////////// CANCEL CHANGE REQUEST NOTIFICATION rAction = "cancelChangeRequest" @@ -406,9 +407,10 @@ class ActionStringHandler @Inject constructor( } val aps = activePlugin.activeAPS ret += "APS: " + (aps as PluginBase).name - if (loopPlugin.lastRun != null) { - if (loopPlugin.lastRun.lastAPSRun != null) ret += "\nLast Run: " + DateUtil.timeString(loopPlugin.lastRun.lastAPSRun) - if (loopPlugin.lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + DateUtil.timeString(loopPlugin.lastRun.lastTBREnact) + val lastRun = loopPlugin.lastRun + if (lastRun != null) { + ret += "\nLast Run: " + DateUtil.timeString(lastRun.lastAPSRun) + if (lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + DateUtil.timeString(lastRun.lastTBREnact) } } else { ret += "LOOP DISABLED\n" diff --git a/app/src/main/java/info/nightscout/androidaps/utils/OKDialog.kt b/app/src/main/java/info/nightscout/androidaps/utils/OKDialog.kt index 186b81ae36..025cb041bb 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/OKDialog.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/OKDialog.kt @@ -11,8 +11,6 @@ import info.nightscout.androidaps.utils.alertDialogs.AlertDialogHelper object OKDialog { @SuppressLint("InflateParams") - @JvmStatic - @JvmOverloads fun show(context: Context, title: String, message: String, runnable: Runnable? = null) { var notEmptytitle = title if (notEmptytitle.isEmpty()) notEmptytitle = context.getString(R.string.message) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt b/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt index 1045f4b5b8..9b03902883 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelper.kt @@ -20,4 +20,5 @@ interface ResourceHelper { fun decodeResource(id : Int) : Bitmap fun getDisplayMetrics(): DisplayMetrics fun dpToPx(dp: Int): Int + fun shortTextMode(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt b/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt index c62130f421..f398534039 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/resources/ResourceHelperImplementation.kt @@ -68,4 +68,6 @@ class ResourceHelperImplementation @Inject constructor(private val context: Cont val scale = context.resources.displayMetrics.density return (dp * scale + 0.5f).toInt() } + + override fun shortTextMode() : Boolean = !gb(R.bool.isTablet) && Config.NSCLIENT } \ No newline at end of file