diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ff5347fce5..321d188d3a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -37,14 +37,25 @@ + android:theme="@style/AppTheme.Launcher" > + + + + + + + rh.gc(R.color.low) + overviewData.isHigh -> rh.gc(R.color.high) + else -> rh.gc(R.color.inrange) + } + ) + views.setImageViewResource(R.id.arrow, trendCalculator.getTrendArrow(overviewData.lastBg).directionToIcon()) + //binding.infoLayout.arrow.setColorFilter(overviewData.lastBgColor(context)) + + val glucoseStatus = glucoseStatusProvider.glucoseStatusData + if (glucoseStatus != null) { + views.setTextViewText(R.id.delta, Profile.toSignedUnitsString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units)) + views.setTextViewText(R.id.avg_delta, Profile.toSignedUnitsString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units)) + views.setTextViewText(R.id.long_avg_delta, Profile.toSignedUnitsString(glucoseStatus.longAvgDelta, glucoseStatus.longAvgDelta * Constants.MGDL_TO_MMOLL, units)) + } else { + views.setTextViewText(R.id.delta, rh.gs(R.string.notavailable)) + views.setTextViewText(R.id.avg_delta, rh.gs(R.string.notavailable)) + views.setTextViewText(R.id.long_avg_delta, rh.gs(R.string.notavailable)) + } + + // strike through if BG is old + if (!overviewData.isActualBg) views.setInt(R.id.bg, "setPaintFlags", Paint.STRIKE_THRU_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG) + else views.setInt(R.id.bg, "setPaintFlags", Paint.ANTI_ALIAS_FLAG) + + views.setTextViewText(R.id.time_ago, dateUtil.minAgo(rh, overviewData.lastBg?.timestamp)) + views.setTextViewText(R.id.time_ago_short, "(" + dateUtil.minAgoShort(overviewData.lastBg?.timestamp) + ")") + } + + private fun updateTemporaryBasal(views: RemoteViews) { + views.setTextViewText(R.id.base_basal, overviewData.temporaryBasalText) + views.setTextColor(R.id.base_basal, overviewData.temporaryBasalColor) + views.setImageViewResource(R.id.base_basal_icon, overviewData.temporaryBasalIcon) + } + + private fun updateExtendedBolus(views: RemoteViews) { + val pump = activePlugin.activePump + views.setTextViewText(R.id.extended_bolus, overviewData.extendedBolusText) + views.setViewVisibility(R.id.extended_layout, (iobCobCalculator.getExtendedBolus(dateUtil.now()) != null && !pump.isFakingTempsByExtendedBoluses).toVisibility()) + } + + private fun updateIobCob(views: RemoteViews) { + views.setTextViewText(R.id.iob, overviewData.iobText) + // cob + var cobText = overviewData.cobInfo?.displayText(rh, dateUtil, isDev = false) ?: rh.gs(R.string.value_unavailable_short) + + val constraintsProcessed = loop.lastRun?.constraintsProcessed + val lastRun = loop.lastRun + if (config.APS && constraintsProcessed != null && lastRun != null) { + if (constraintsProcessed.carbsReq > 0) { + //only display carbsreq when carbs have not been entered recently + if (overviewData.lastCarbsTime < lastRun.lastAPSRun) { + cobText += " | " + constraintsProcessed.carbsReq + " " + rh.gs(R.string.required) + } + } + } + views.setTextViewText(R.id.cob, cobText) + } + + private fun updateTemporaryTarget(views: RemoteViews) { + val units = profileFunction.getUnits() + if (overviewData.temporaryTarget?.isInProgress(dateUtil) == false) overviewData.temporaryTarget = null + val tempTarget = overviewData.temporaryTarget + if (tempTarget != null) { + // this is crashing, use background as text for now + //views.setTextColor(R.id.temp_target, rh.gc(R.color.ribbonTextWarning)) + //views.setInt(R.id.temp_target, "setBackgroundColor", rh.gc(R.color.ribbonWarning)) + views.setTextColor(R.id.temp_target, rh.gc(R.color.ribbonWarning)) + views.setTextViewText(R.id.temp_target, Profile.toTargetRangeString(tempTarget.lowTarget, tempTarget.highTarget, GlucoseUnit.MGDL, units) + " " + dateUtil.untilString(tempTarget.end, rh)) + } else { + // If the target is not the same as set in the profile then oref has overridden it + profileFunction.getProfile()?.let { profile -> + val targetUsed = loop.lastRun?.constraintsProcessed?.targetBG ?: 0.0 + + if (targetUsed != 0.0 && abs(profile.getTargetMgdl() - targetUsed) > 0.01) { + aapsLogger.debug("Adjusted target. Profile: ${profile.getTargetMgdl()} APS: $targetUsed") + views.setTextViewText(R.id.temp_target, Profile.toTargetRangeString(targetUsed, targetUsed, GlucoseUnit.MGDL, units)) + // this is crashing, use background as text for now + //views.setTextColor(R.id.temp_target, rh.gc(R.color.ribbonTextWarning)) + //views.setInt(R.id.temp_target, "setBackgroundResource", rh.gc(R.color.tempTargetBackground)) + views.setTextColor(R.id.temp_target, rh.gc(R.color.ribbonWarning)) + } else { + // this is crashing, use background as text for now + //views.setTextColor(R.id.temp_target, rh.gc(R.color.ribbonTextDefault)) + //views.setInt(R.id.temp_target, "setBackgroundColor", rh.gc(R.color.ribbonDefault)) + views.setTextColor(R.id.temp_target, rh.gc(R.color.ribbonTextDefault)) + views.setTextViewText(R.id.temp_target, Profile.toTargetRangeString(profile.getTargetLowMgdl(), profile.getTargetHighMgdl(), GlucoseUnit.MGDL, units)) + } + } + } + } + + fun updateProfile(views: RemoteViews) { + val profileTextColor = + profileFunction.getProfile()?.let { + if (it is ProfileSealed.EPS) { + if (it.value.originalPercentage != 100 || it.value.originalTimeshift != 0L || it.value.originalDuration != 0L) + rh.gc(R.color.ribbonWarning) + else rh.gc(R.color.ribbonTextDefault) + } else if (it is ProfileSealed.PS) { + rh.gc(R.color.ribbonTextDefault) + } else { + rh.gc(R.color.ribbonTextDefault) + } + } ?: rh.gc(R.color.ribbonCritical) + + views.setTextViewText(R.id.active_profile, profileFunction.getProfileNameWithRemainingTime()) + // this is crashing, use background as text for now + //views.setInt(R.id.active_profile, "setBackgroundColor", profileBackgroundColor) + //views.setTextColor(R.id.active_profile, profileTextColor) + views.setTextColor(R.id.active_profile, profileTextColor) + } +} + +internal fun updateWidget(context: Context) { + context.sendBroadcast(Intent().also { + it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, AppWidgetManager.getInstance(context).getAppWidgetIds(ComponentName(context, Widget::class.java))) + it.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE + }) +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/di/UIModule.kt b/app/src/main/java/info/nightscout/androidaps/di/UIModule.kt index 294fa28f0d..13083f32a5 100644 --- a/app/src/main/java/info/nightscout/androidaps/di/UIModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/di/UIModule.kt @@ -2,10 +2,13 @@ package info.nightscout.androidaps.di import dagger.Module import dagger.android.ContributesAndroidInjector +import info.nightscout.androidaps.Widget import info.nightscout.androidaps.skins.SkinListPreference @Module @Suppress("unused") abstract class UIModule { + @ContributesAndroidInjector abstract fun skinListPreferenceInjector(): SkinListPreference + @ContributesAndroidInjector abstract fun aapsWidgetInjector(): Widget } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt index f25e01c0db..ad2450d461 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewData.kt @@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.overview import android.content.Context import android.graphics.DashPathEffect import android.graphics.Paint +import androidx.annotation.ColorInt import com.jjoe64.graphview.series.BarGraphSeries import com.jjoe64.graphview.series.DataPoint import com.jjoe64.graphview.series.LineGraphSeries @@ -129,23 +130,23 @@ class OverviewData @Inject constructor( var lastBg: GlucoseValue? = null - private val isLow: Boolean + val isLow: Boolean get() = lastBg?.let { lastBg -> lastBg.valueToUnits(profileFunction.getUnits()) < defaultValueHelper.determineLowLine() } ?: false - private val isHigh: Boolean + val isHigh: Boolean get() = lastBg?.let { lastBg -> lastBg.valueToUnits(profileFunction.getUnits()) > defaultValueHelper.determineHighLine() } ?: false - fun lastBgColor(context: Context?): Int { - return when { + @ColorInt + fun lastBgColor(context: Context?): Int = + when { isLow -> rh.gac(context, R.attr.bgLow) isHigh -> rh.gac(context, R.attr.highColor) else -> rh.gac(context, R.attr.bgInRange) } - } val lastBgDescription: String get() = when { diff --git a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt index dc705c4a84..01c19acbcc 100644 --- a/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt +++ b/app/src/main/java/info/nightscout/androidaps/receivers/KeepAliveWorker.kt @@ -15,6 +15,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin import info.nightscout.androidaps.queue.commands.Command +import info.nightscout.androidaps.updateWidget import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.LocalAlertUtils @@ -86,6 +87,7 @@ class KeepAliveWorker( ) } + updateWidget(context) localAlertUtils.shortenSnoozeInterval() localAlertUtils.checkStaleBGAlert() checkPump() diff --git a/app/src/main/res/drawable-nodpi/widget_preview.png b/app/src/main/res/drawable-nodpi/widget_preview.png new file mode 100644 index 0000000000..53f2854fa4 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/widget_preview.png differ diff --git a/app/src/main/res/drawable-v21/app_widget_background.xml b/app/src/main/res/drawable-v21/app_widget_background.xml new file mode 100644 index 0000000000..47e7ec2a04 --- /dev/null +++ b/app/src/main/res/drawable-v21/app_widget_background.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml b/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml new file mode 100644 index 0000000000..e1b8cf7827 --- /dev/null +++ b/app/src/main/res/drawable-v21/app_widget_inner_view_background.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_layout.xml b/app/src/main/res/layout/widget_layout.xml new file mode 100644 index 0000000000..3403ed4d64 --- /dev/null +++ b/app/src/main/res/layout/widget_layout.xml @@ -0,0 +1,344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000000..e1eb8ded41 --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000000..7781ac86bc --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 8542005550..c64cb175a7 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,2 +1,9 @@ + + + + 0dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2430631840..fcc0b0541b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1208,4 +1208,5 @@ Above Show loop records Hide loop records + AndroidAPS widget diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..7b1ecb719f --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000000..3b74ec17b1 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/widget_info.xml b/app/src/main/res/xml/widget_info.xml new file mode 100644 index 0000000000..8fb146e8bb --- /dev/null +++ b/app/src/main/res/xml/widget_info.xml @@ -0,0 +1,11 @@ + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 141c619741..a83d4ba7f6 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,7 @@ plugins { id "io.gitlab.arturbosch.detekt" version "1.19.0" id "org.jlleitschuh.gradle.ktlint" version "10.2.1" id 'org.barfuin.gradle.jacocolog' version '2.0.0' + id 'org.jetbrains.kotlin.android' version '1.6.10' apply false } allprojects { diff --git a/shared/src/main/java/info/nightscout/shared/logging/LTag.kt b/shared/src/main/java/info/nightscout/shared/logging/LTag.kt index fa77e408dc..df6aafa82b 100644 --- a/shared/src/main/java/info/nightscout/shared/logging/LTag.kt +++ b/shared/src/main/java/info/nightscout/shared/logging/LTag.kt @@ -24,5 +24,6 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires SMS("SMS"), TIDEPOOL("TIDEPOOL"), UI("UI", defaultValue = false), - WEAR("WEAR") + WEAR("WEAR"), + WIDGET("WIDGET") } \ No newline at end of file