widget
This commit is contained in:
parent
07c7ac4818
commit
08d7a38dfb
19 changed files with 679 additions and 10 deletions
|
@ -37,14 +37,25 @@
|
||||||
<application
|
<application
|
||||||
android:name=".MainApp"
|
android:name=".MainApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
android:backupAgent=".utils.SPBackupAgent"
|
||||||
|
android:fullBackupOnly="false"
|
||||||
android:icon="${appIcon}"
|
android:icon="${appIcon}"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:restoreAnyVersion="true"
|
||||||
android:roundIcon="${appIconRound}"
|
android:roundIcon="${appIconRound}"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme.Launcher"
|
android:theme="@style/AppTheme.Launcher" >
|
||||||
android:fullBackupOnly="false"
|
<receiver
|
||||||
android:backupAgent=".utils.SPBackupAgent"
|
android:name=".Widget"
|
||||||
android:restoreAnyVersion="true">
|
android:exported="true" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/widget_info" />
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.backup.api_key"
|
android:name="com.google.android.backup.api_key"
|
||||||
|
|
|
@ -6,6 +6,8 @@ import android.content.IntentFilter
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.HandlerThread
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import androidx.work.Data
|
import androidx.work.Data
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
|
@ -76,6 +78,9 @@ class MainApp : DaggerApplication() {
|
||||||
@Inject lateinit var profileSwitchPlugin: ThemeSwitcherPlugin
|
@Inject lateinit var profileSwitchPlugin: ThemeSwitcherPlugin
|
||||||
@Inject lateinit var localAlertUtils: LocalAlertUtils
|
@Inject lateinit var localAlertUtils: LocalAlertUtils
|
||||||
|
|
||||||
|
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||||
|
private lateinit var refreshWidget: Runnable
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
aapsLogger.debug("onCreate")
|
aapsLogger.debug("onCreate")
|
||||||
|
@ -133,6 +138,13 @@ class MainApp : DaggerApplication() {
|
||||||
localAlertUtils.preSnoozeAlarms()
|
localAlertUtils.preSnoozeAlarms()
|
||||||
doMigrations()
|
doMigrations()
|
||||||
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
|
uel.log(UserEntry.Action.START_AAPS, UserEntry.Sources.Aaps)
|
||||||
|
|
||||||
|
// schedule widget update
|
||||||
|
refreshWidget = Runnable {
|
||||||
|
handler.postDelayed(refreshWidget, 60000)
|
||||||
|
updateWidget(this)
|
||||||
|
}
|
||||||
|
handler.postDelayed(refreshWidget, 60000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setRxErrorHandler() {
|
private fun setRxErrorHandler() {
|
||||||
|
|
202
app/src/main/java/info/nightscout/androidaps/Widget.kt
Normal file
202
app/src/main/java/info/nightscout/androidaps/Widget.kt
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
package info.nightscout.androidaps
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProvider
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.widget.RemoteViews
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.data.ProfileSealed
|
||||||
|
import info.nightscout.androidaps.database.interfaces.end
|
||||||
|
import info.nightscout.androidaps.extensions.directionToIcon
|
||||||
|
import info.nightscout.androidaps.extensions.isInProgress
|
||||||
|
import info.nightscout.androidaps.extensions.toVisibility
|
||||||
|
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||||
|
import info.nightscout.androidaps.interfaces.*
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.OverviewData
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.TrendCalculator
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.logging.LTag
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of App Widget functionality.
|
||||||
|
*/
|
||||||
|
class Widget : AppWidgetProvider() {
|
||||||
|
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var overviewData: OverviewData
|
||||||
|
@Inject lateinit var trendCalculator: TrendCalculator
|
||||||
|
@Inject lateinit var rh: ResourceHelper
|
||||||
|
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||||
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var activePlugin: ActivePlugin
|
||||||
|
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||||
|
@Inject lateinit var loop: Loop
|
||||||
|
@Inject lateinit var config: Config
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent?) {
|
||||||
|
(context.applicationContext as HasAndroidInjector).androidInjector().inject(this)
|
||||||
|
super.onReceive(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||||
|
// There may be multiple widgets active, so update all of them
|
||||||
|
for (appWidgetId in appWidgetIds) {
|
||||||
|
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnabled(context: Context) {
|
||||||
|
// Enter relevant functionality for when the first widget is created
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisabled(context: Context) {
|
||||||
|
// Enter relevant functionality for when the last widget is disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
|
||||||
|
aapsLogger.debug(LTag.WIDGET, "updateAppWidget called")
|
||||||
|
val views = RemoteViews(context.packageName, R.layout.widget_layout)
|
||||||
|
|
||||||
|
updateBg(views)
|
||||||
|
updateTemporaryBasal(views)
|
||||||
|
updateExtendedBolus(views)
|
||||||
|
updateIobCob(views)
|
||||||
|
updateTemporaryTarget(views)
|
||||||
|
updateProfile(views)
|
||||||
|
|
||||||
|
// Instruct the widget manager to update the widget
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBg(views: RemoteViews) {
|
||||||
|
val units = profileFunction.getUnits()
|
||||||
|
views.setTextViewText(R.id.bg, overviewData.lastBg?.valueToUnitsString(units) ?: rh.gs(R.string.notavailable))
|
||||||
|
views.setTextColor(
|
||||||
|
R.id.bg, when {
|
||||||
|
overviewData.isLow -> 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
|
||||||
|
})
|
||||||
|
}
|
|
@ -2,10 +2,13 @@ package info.nightscout.androidaps.di
|
||||||
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Widget
|
||||||
import info.nightscout.androidaps.skins.SkinListPreference
|
import info.nightscout.androidaps.skins.SkinListPreference
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
abstract class UIModule {
|
abstract class UIModule {
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun skinListPreferenceInjector(): SkinListPreference
|
@ContributesAndroidInjector abstract fun skinListPreferenceInjector(): SkinListPreference
|
||||||
|
@ContributesAndroidInjector abstract fun aapsWidgetInjector(): Widget
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.overview
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.DashPathEffect
|
import android.graphics.DashPathEffect
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
import com.jjoe64.graphview.series.BarGraphSeries
|
import com.jjoe64.graphview.series.BarGraphSeries
|
||||||
import com.jjoe64.graphview.series.DataPoint
|
import com.jjoe64.graphview.series.DataPoint
|
||||||
import com.jjoe64.graphview.series.LineGraphSeries
|
import com.jjoe64.graphview.series.LineGraphSeries
|
||||||
|
@ -129,23 +130,23 @@ class OverviewData @Inject constructor(
|
||||||
|
|
||||||
var lastBg: GlucoseValue? = null
|
var lastBg: GlucoseValue? = null
|
||||||
|
|
||||||
private val isLow: Boolean
|
val isLow: Boolean
|
||||||
get() = lastBg?.let { lastBg ->
|
get() = lastBg?.let { lastBg ->
|
||||||
lastBg.valueToUnits(profileFunction.getUnits()) < defaultValueHelper.determineLowLine()
|
lastBg.valueToUnits(profileFunction.getUnits()) < defaultValueHelper.determineLowLine()
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
private val isHigh: Boolean
|
val isHigh: Boolean
|
||||||
get() = lastBg?.let { lastBg ->
|
get() = lastBg?.let { lastBg ->
|
||||||
lastBg.valueToUnits(profileFunction.getUnits()) > defaultValueHelper.determineHighLine()
|
lastBg.valueToUnits(profileFunction.getUnits()) > defaultValueHelper.determineHighLine()
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
fun lastBgColor(context: Context?): Int {
|
@ColorInt
|
||||||
return when {
|
fun lastBgColor(context: Context?): Int =
|
||||||
|
when {
|
||||||
isLow -> rh.gac(context, R.attr.bgLow)
|
isLow -> rh.gac(context, R.attr.bgLow)
|
||||||
isHigh -> rh.gac(context, R.attr.highColor)
|
isHigh -> rh.gac(context, R.attr.highColor)
|
||||||
else -> rh.gac(context, R.attr.bgInRange)
|
else -> rh.gac(context, R.attr.bgInRange)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val lastBgDescription: String
|
val lastBgDescription: String
|
||||||
get() = when {
|
get() = when {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
|
import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
||||||
import info.nightscout.androidaps.queue.commands.Command
|
import info.nightscout.androidaps.queue.commands.Command
|
||||||
|
import info.nightscout.androidaps.updateWidget
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.LocalAlertUtils
|
import info.nightscout.androidaps.utils.LocalAlertUtils
|
||||||
|
@ -86,6 +87,7 @@ class KeepAliveWorker(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateWidget(context)
|
||||||
localAlertUtils.shortenSnoozeInterval()
|
localAlertUtils.shortenSnoozeInterval()
|
||||||
localAlertUtils.checkStaleBGAlert()
|
localAlertUtils.checkStaleBGAlert()
|
||||||
checkPump()
|
checkPump()
|
||||||
|
|
BIN
app/src/main/res/drawable-nodpi/widget_preview.png
Normal file
BIN
app/src/main/res/drawable-nodpi/widget_preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
11
app/src/main/res/drawable-v21/app_widget_background.xml
Normal file
11
app/src/main/res/drawable-v21/app_widget_background.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Background for widgets to make the rounded corners based on the
|
||||||
|
appWidgetRadius attribute value
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<corners android:radius="?attr/appWidgetRadius" />
|
||||||
|
<solid android:color="?android:attr/colorBackground" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Background for views inside widgets to make the rounded corners based on the
|
||||||
|
appWidgetInnerRadius attribute value
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<corners android:radius="?attr/appWidgetInnerRadius" />
|
||||||
|
<solid android:color="?android:attr/colorAccent" />
|
||||||
|
</shape>
|
344
app/src/main/res/layout/widget_layout.xml
Normal file
344
app/src/main/res/layout/widget_layout.xml
Normal file
|
@ -0,0 +1,344 @@
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
style="@style/Widget.AndroidAPS.AppWidget.Container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:theme="@style/AppTheme.Launcher.AppWidgetContainer">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/active_profile"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical|center_horizontal"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/temp_target"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical|center_horizontal"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bg"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="00.0"
|
||||||
|
android:textSize="60sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/arrows_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/arrow"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/trend_arrow"
|
||||||
|
android:src="@drawable/ic_flat" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/time_ago"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/deltas_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="end|center_vertical"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:contentDescription="last delta"
|
||||||
|
android:text="Δ: "
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/delta"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:contentDescription="15 minutes delta"
|
||||||
|
android:text="15m Δ: "
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/avg_delta"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:contentDescription="40 minutes delta"
|
||||||
|
android:text="40m Δ: "
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/long_avg_delta"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAlignment="textEnd"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/iob_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:contentDescription="@string/iob"
|
||||||
|
android:src="@drawable/ic_bolus" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/iob"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="3dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/cob_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/carbs_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:background="@drawable/anim_carbs"
|
||||||
|
android:contentDescription="@string/cob" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cob"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="3dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/basal_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/base_basal_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:contentDescription="@string/basal"
|
||||||
|
android:src="@drawable/ic_cp_basal_no_tbr" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/base_basal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="3dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/extended_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:contentDescription="@string/extended_bolus"
|
||||||
|
android:src="@drawable/ic_actions_startextbolus" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/extended_bolus"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="3dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/as_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/sensitivity_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:contentDescription="@string/a11y_autosenslabel"
|
||||||
|
android:src="@drawable/ic_swap_vert_black_48dp_green" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sensitivity"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="3dp"
|
||||||
|
android:paddingBottom="3dp"
|
||||||
|
android:text="n/a"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
11
app/src/main/res/values-v21/styles.xml
Normal file
11
app/src/main/res/values-v21/styles.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<resources>
|
||||||
|
<style name="Widget.AndroidAPS.AppWidget.Container" parent="android:Widget">
|
||||||
|
<item name="android:padding">?attr/appWidgetPadding</item>
|
||||||
|
<item name="android:background">@drawable/app_widget_background</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.AndroidAPS.AppWidget.InnerView" parent="android:Widget">
|
||||||
|
<item name="android:padding">?attr/appWidgetPadding</item>
|
||||||
|
<item name="android:background">@drawable/app_widget_inner_view_background</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
7
app/src/main/res/values/attrs.xml
Normal file
7
app/src/main/res/values/attrs.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="AppWidgetAttrs">
|
||||||
|
<attr name="appWidgetPadding" format="dimension" />
|
||||||
|
<attr name="appWidgetInnerRadius" format="dimension" />
|
||||||
|
<attr name="appWidgetRadius" format="dimension" />
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
|
@ -1,2 +1,9 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Refer to App Widget Documentation for margin information
|
||||||
|
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
|
||||||
|
-->
|
||||||
|
<dimen name="widget_margin">0dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1208,4 +1208,5 @@
|
||||||
<string name="above" comment="above "in range"">Above</string>
|
<string name="above" comment="above "in range"">Above</string>
|
||||||
<string name="show_loop_records">Show loop records</string>
|
<string name="show_loop_records">Show loop records</string>
|
||||||
<string name="show_hide_records">Hide loop records</string>
|
<string name="show_hide_records">Hide loop records</string>
|
||||||
|
<string name="widget_description">AndroidAPS widget</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
11
app/src/main/res/values/styles.xml
Normal file
11
app/src/main/res/values/styles.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<resources>
|
||||||
|
<style name="Widget.AndroidAPS.AppWidget.Container" parent="android:Widget">
|
||||||
|
<item name="android:id">@android:id/background</item>
|
||||||
|
<item name="android:background">?android:attr/colorBackground</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.AndroidAPS.AppWidget.InnerView" parent="android:Widget">
|
||||||
|
<item name="android:background">?android:attr/colorBackground</item>
|
||||||
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
22
app/src/main/res/values/themes.xml
Normal file
22
app/src/main/res/values/themes.xml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<resources>
|
||||||
|
<style name="AppTheme.Launcher.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
|
||||||
|
<!-- Radius of the outer bound of widgets to make the rounded corners -->
|
||||||
|
<item name="appWidgetRadius">16dp</item>
|
||||||
|
<!--
|
||||||
|
Radius of the inner view's bound of widgets to make the rounded corners.
|
||||||
|
It needs to be 8dp or less than the value of appWidgetRadius
|
||||||
|
-->
|
||||||
|
<item name="appWidgetInnerRadius">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme.Launcher.AppWidgetContainer"
|
||||||
|
parent="AppTheme.Launcher.AppWidgetContainerParent">
|
||||||
|
<!-- Apply padding to avoid the content of the widget colliding with the rounded corners -->
|
||||||
|
<item name="appWidgetPadding">16dp</item>
|
||||||
|
|
||||||
|
|
||||||
|
<item name="icBolusColor">@color/colorInsulinButton</item>
|
||||||
|
<item name="icBolusCarbsColor">@color/colorCarbsButton</item>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</resources>
|
11
app/src/main/res/xml/widget_info.xml
Normal file
11
app/src/main/res/xml/widget_info.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:minWidth="250dp"
|
||||||
|
android:minHeight="110dp"
|
||||||
|
android:updatePeriodMillis="86400000"
|
||||||
|
android:previewImage="@drawable/widget_preview"
|
||||||
|
android:initialLayout="@layout/widget_layout"
|
||||||
|
android:description="@string/widget_description"
|
||||||
|
android:widgetCategory="home_screen"
|
||||||
|
android:initialKeyguardLayout="@layout/widget_layout"
|
||||||
|
/>
|
|
@ -58,6 +58,7 @@ plugins {
|
||||||
id "io.gitlab.arturbosch.detekt" version "1.19.0"
|
id "io.gitlab.arturbosch.detekt" version "1.19.0"
|
||||||
id "org.jlleitschuh.gradle.ktlint" version "10.2.1"
|
id "org.jlleitschuh.gradle.ktlint" version "10.2.1"
|
||||||
id 'org.barfuin.gradle.jacocolog' version '2.0.0'
|
id 'org.barfuin.gradle.jacocolog' version '2.0.0'
|
||||||
|
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
|
|
@ -24,5 +24,6 @@ enum class LTag(val tag: String, val defaultValue : Boolean = true, val requires
|
||||||
SMS("SMS"),
|
SMS("SMS"),
|
||||||
TIDEPOOL("TIDEPOOL"),
|
TIDEPOOL("TIDEPOOL"),
|
||||||
UI("UI", defaultValue = false),
|
UI("UI", defaultValue = false),
|
||||||
WEAR("WEAR")
|
WEAR("WEAR"),
|
||||||
|
WIDGET("WIDGET")
|
||||||
}
|
}
|
Loading…
Reference in a new issue