BigChartWatchface based on BaseWatchFace

This commit is contained in:
Milos Kozak 2022-04-25 08:38:35 +02:00
parent 2b00ea745a
commit de6c7d2ffe
2 changed files with 18 additions and 321 deletions

View file

@ -295,7 +295,7 @@ abstract class BaseWatchFace : WatchFace() {
bIsRound = screenInsets.isRound bIsRound = screenInsets.isRound
} }
fun performViewSetup() { private fun performViewSetup() {
mTime = layoutView?.findViewById(R.id.watch_time) mTime = layoutView?.findViewById(R.id.watch_time)
mHour = layoutView?.findViewById(R.id.hour) mHour = layoutView?.findViewById(R.id.hour)
mMinute = layoutView?.findViewById(R.id.minute) mMinute = layoutView?.findViewById(R.id.minute)
@ -344,7 +344,7 @@ abstract class BaseWatchFace : WatchFace() {
return (System.currentTimeMillis() - singleBg.timeStamp).toDouble() return (System.currentTimeMillis() - singleBg.timeStamp).toDouble()
} }
private fun readingAge(shortString: Boolean): String { protected fun readingAge(shortString: Boolean): String {
if (singleBg.timeStamp == 0L) { if (singleBg.timeStamp == 0L) {
return if (shortString) "--" else "-- Minute ago" return if (shortString) "--" else "-- Minute ago"
} }
@ -436,7 +436,7 @@ abstract class BaseWatchFace : WatchFace() {
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun setDataFields() { open fun setDataFields() {
setDateAndTime() setDateAndTime()
mSgv?.text = singleBg.sgvString mSgv?.text = singleBg.sgvString
mSgv?.visibility = sp.getBoolean(R.string.key_show_bg, true).toVisibilityKeepSpace() mSgv?.visibility = sp.getBoolean(R.string.key_show_bg, true).toVisibilityKeepSpace()
@ -497,7 +497,7 @@ abstract class BaseWatchFace : WatchFace() {
invalidate() invalidate()
} }
private fun setDateAndTime() { protected fun setDateAndTime() {
mTime?.text = dateUtil.timeString() mTime?.text = dateUtil.timeString()
mHour?.text = dateUtil.hourString() mHour?.text = dateUtil.hourString()
mMinute?.text = dateUtil.minuteString() mMinute?.text = dateUtil.minuteString()
@ -516,7 +516,7 @@ abstract class BaseWatchFace : WatchFace() {
} }
} }
private fun strikeThroughSgvIfNeeded() { protected fun strikeThroughSgvIfNeeded() {
mSgv?.let { mSgv -> mSgv?.let { mSgv ->
if (ageLevel() <= 0 && singleBg.timeStamp > 0) mSgv.paintFlags = mSgv.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG if (ageLevel() <= 0 && singleBg.timeStamp > 0) mSgv.paintFlags = mSgv.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
else mSgv.paintFlags = mSgv.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv() else mSgv.paintFlags = mSgv.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()

View file

@ -2,288 +2,23 @@
package info.nightscout.androidaps.watchfaces package info.nightscout.androidaps.watchfaces
import android.annotation.SuppressLint import androidx.annotation.LayoutRes
import android.content.Intent
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Point
import android.graphics.Rect
import android.os.PowerManager
import android.support.wearable.watchface.WatchFaceStyle
import android.view.LayoutInflater
import android.view.View
import android.view.WindowInsets
import android.view.WindowManager
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.ustwo.clockwise.common.WatchFaceTime
import com.ustwo.clockwise.common.WatchMode import com.ustwo.clockwise.common.WatchMode
import com.ustwo.clockwise.common.WatchShape
import com.ustwo.clockwise.wearable.WatchFace
import dagger.android.AndroidInjection
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.EventWearToMobile
import info.nightscout.androidaps.extensions.toVisibility
import info.nightscout.androidaps.interaction.menus.MainMenuActivity
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.weardata.EventData
import info.nightscout.shared.weardata.EventData.ActionResendData
import info.nightscout.shared.weardata.EventData.SingleBg
import info.nightscout.shared.weardata.EventData.TreatmentData
import io.reactivex.rxjava3.disposables.CompositeDisposable
import lecho.lib.hellocharts.view.LineChartView
import javax.inject.Inject
import kotlin.math.floor
class BigChartWatchface : WatchFace() { class BigChartWatchface : BaseWatchFace() {
@Inject lateinit var rxBus: RxBus @LayoutRes override fun layoutResource(): Int =
@Inject lateinit var aapsSchedulers: AapsSchedulers if (resources.displayMetrics.widthPixels < SCREEN_SIZE_SMALL || resources.displayMetrics.heightPixels < SCREEN_SIZE_SMALL) R.layout.activity_bigchart_small
@Inject lateinit var aapsLogger: AAPSLogger else R.layout.activity_bigchart
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
private var disposable = CompositeDisposable() override fun setDataFields() {
super.setDataFields()
private var singleBg = SingleBg(0, "---", "-", "--", "--", "--", 0, 0.0, 0.0, 0.0, 0)
private var status = EventData.Status("no status", "IOB", "-.--", false, "--g", "-.--U/h", "--", "--", -1, "--", false, 1)
private var treatmentData = TreatmentData(java.util.ArrayList(), java.util.ArrayList(), java.util.ArrayList(), java.util.ArrayList())
private var graphData = EventData.GraphData(java.util.ArrayList())
private var mTime: TextView? = null
private var mSgv: TextView? = null
private var mTimestamp: TextView? = null
private var mDelta: TextView? = null
private var mAvgDelta: TextView? = null
private var mRelativeLayout: RelativeLayout? = null
private var ageLevel = 1
private var highColor = Color.YELLOW
private var lowColor = Color.RED
private var midColor = Color.WHITE
private var gridColour = Color.WHITE
private var basalBackgroundColor = Color.BLUE
private var basalCenterColor = Color.BLUE
private var bolusColor = Color.MAGENTA
private var carbsColor = Color.GREEN
private var pointSize = 2
private var lowResMode = false
private var layoutSet = false
var chart: LineChartView? = null
private var bgDataList = ArrayList<SingleBg>()
private var wakeLock: PowerManager.WakeLock? = null
private var layoutView: View? = null
private val displaySize = Point()
private var specW = 0
private var specH = 0
private var mStatus: TextView? = null
private var chartTapTime = 0L
private var sgvTapTime = 0L
@SuppressLint("InflateParams")
override fun onCreate() {
AndroidInjection.inject(this)
super.onCreate()
val display = (getSystemService(WINDOW_SERVICE) as WindowManager).defaultDisplay
display.getSize(displaySize)
wakeLock = (getSystemService(POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:BIGChart")
specW = View.MeasureSpec.makeMeasureSpec(displaySize.x, View.MeasureSpec.EXACTLY)
specH = View.MeasureSpec.makeMeasureSpec(displaySize.y, View.MeasureSpec.EXACTLY)
val inflater = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater
val metrics = resources.displayMetrics
layoutView = if (metrics.widthPixels < SCREEN_SIZE_SMALL || metrics.heightPixels < SCREEN_SIZE_SMALL) {
inflater.inflate(R.layout.activity_bigchart_small, null)
} else {
inflater.inflate(R.layout.activity_bigchart, null)
}
performViewSetup()
disposable.add(rxBus
.toObservable(SingleBg::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event ->
aapsLogger.debug(LTag.WEAR, "SingleBg received")
singleBg = event
mSgv?.text = singleBg.sgvString
mSgv?.let { mSgv ->
if (ageLevel() <= 0) mSgv.paintFlags = mSgv.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
else mSgv.paintFlags = mSgv.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}
mTime?.text = dateUtil.timeString()
mDelta?.text = singleBg.delta
mAvgDelta?.text = singleBg.avgDelta
}
)
disposable.add(rxBus
.toObservable(TreatmentData::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event -> treatmentData = event }
)
disposable.add(rxBus
.toObservable(EventData.GraphData::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event -> graphData = event }
)
disposable.add(rxBus
.toObservable(EventData.Status::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event ->
// this event is received as last batch of data
aapsLogger.debug(LTag.WEAR, "Status received")
status = event
showAgeAndStatus()
addToWatchSet()
mRelativeLayout?.measure(specW, specH)
mRelativeLayout?.layout(0, 0, mRelativeLayout?.measuredWidth ?: 0, mRelativeLayout?.measuredHeight ?: 0)
invalidate()
setColor()
}
)
disposable.add(rxBus
.toObservable(EventData.Preferences::class.java)
.observeOn(aapsSchedulers.main)
.subscribe {
setColor()
if (layoutSet) {
showAgeAndStatus()
mRelativeLayout?.measure(specW, specH)
mRelativeLayout?.layout(0, 0, mRelativeLayout?.measuredWidth ?: 0, mRelativeLayout?.measuredHeight ?: 0)
}
invalidate()
}
)
}
override fun onLayout(shape: WatchShape, screenBounds: Rect, screenInsets: WindowInsets) {
super.onLayout(shape, screenBounds, screenInsets)
layoutView?.onApplyWindowInsets(screenInsets)
}
private fun performViewSetup() {
mTime = layoutView?.findViewById(R.id.watch_time)
mSgv = layoutView?.findViewById(R.id.sgv)
mTimestamp = layoutView?.findViewById(R.id.timestamp)
mDelta = layoutView?.findViewById(R.id.delta)
mAvgDelta = layoutView?.findViewById(R.id.avgdelta)
mRelativeLayout = layoutView?.findViewById(R.id.main_layout)
chart = layoutView?.findViewById(R.id.chart)
mStatus = layoutView?.findViewById(R.id.externaltstatus)
layoutSet = true
showAgeAndStatus()
mRelativeLayout?.measure(specW, specH)
mRelativeLayout?.layout(0, 0, mRelativeLayout?.measuredWidth ?: 0, mRelativeLayout?.measuredHeight ?: 0)
rxBus.send(EventWearToMobile(ActionResendData("BIGChart:performViewSetup")))
wakeLock?.acquire(50)
}
override fun onTapCommand(tapType: Int, x: Int, y: Int, eventTime: Long) {
chart?.let { chart ->
mSgv?.let { mSgv ->
val extra = (mSgv.right - mSgv.left) / 2
if (tapType == TAP_TYPE_TAP && x >= chart.left && x <= chart.right && y >= chart.top && y <= chart.bottom) {
if (eventTime - chartTapTime < 800) {
changeChartTimeframe()
}
chartTapTime = eventTime
} else if (tapType == TAP_TYPE_TAP && x + extra >= mSgv.left && x - extra <= mSgv.right && y >= mSgv.top && y <= mSgv.bottom) {
if (eventTime - sgvTapTime < 800) {
val intent = Intent(this, MainMenuActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
sgvTapTime = eventTime
}
}
}
}
private fun changeChartTimeframe() {
var timeframe = sp.getInt(R.string.key_chart_time_frame, 3)
timeframe = timeframe % 5 + 1
sp.putInt(R.string.key_chart_time_frame, timeframe)
}
override fun onWatchModeChanged(watchMode: WatchMode) {
if (lowResMode xor isLowRes(watchMode)) { //if there was a change in lowResMode
lowResMode = isLowRes(watchMode)
setColor()
} else if (!sp.getBoolean("dark", true)) {
//in bright mode: different colours if active:
setColor()
}
}
private fun isLowRes(watchMode: WatchMode): Boolean {
return watchMode == WatchMode.LOW_BIT || watchMode == WatchMode.LOW_BIT_BURN_IN
}
override fun getWatchFaceStyle(): WatchFaceStyle {
return WatchFaceStyle.Builder(this).setAcceptsTapEvents(true).build()
}
private fun ageLevel(): Int {
return if (timeSince() <= 1000 * 60 * 12) {
1
} else {
0
}
}
fun timeSince(): Double {
return (System.currentTimeMillis() - singleBg.timeStamp).toDouble()
}
private fun readingAge(): String =
if (singleBg.timeStamp == 0L) "--'"
else "${floor(timeSince() / (1000 * 60)).toInt()}'"
override fun onDestroy() {
disposable.clear()
super.onDestroy()
}
override fun onDraw(canvas: Canvas) {
if (layoutSet) {
mRelativeLayout?.draw(canvas)
}
}
override fun onTimeChanged(oldTime: WatchFaceTime, newTime: WatchFaceTime) {
if (layoutSet && (newTime.hasHourChanged(oldTime) || newTime.hasMinuteChanged(oldTime))) {
wakeLock?.acquire(50)
mTime?.text = dateUtil.timeString()
showAgeAndStatus()
mSgv?.let { mSgv ->
if (ageLevel() <= 0) mSgv.paintFlags = mSgv.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
else mSgv.paintFlags = mSgv.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}
missedReadingAlert()
mRelativeLayout?.measure(specW, specH)
mRelativeLayout?.layout(0, 0, mRelativeLayout?.measuredWidth ?: 0, mRelativeLayout?.measuredHeight ?: 0)
}
}
private fun showAgeAndStatus() {
mTimestamp?.text = readingAge()
mAvgDelta?.visibility = sp.getBoolean(R.string.key_show_external_status, true).toVisibility()
mStatus?.visibility = sp.getBoolean(R.string.key_show_external_status, true).toVisibility()
mStatus?.text = status.externalStatus + if (sp.getBoolean(R.string.key_show_cob, true)) (" " + this.status.cob) else "" mStatus?.text = status.externalStatus + if (sp.getBoolean(R.string.key_show_cob, true)) (" " + this.status.cob) else ""
} }
private fun setColor() { override fun setColorLowRes() {
when {
lowResMode -> setColorLowRes()
sp.getBoolean("dark", true) -> setColorDark()
else -> setColorBright()
}
}
private fun setColorLowRes() {
mTime?.setTextColor(ContextCompat.getColor(this, R.color.dark_mTime)) mTime?.setTextColor(ContextCompat.getColor(this, R.color.dark_mTime))
mStatus?.setTextColor(ContextCompat.getColor(this, R.color.dark_statusView)) mStatus?.setTextColor(ContextCompat.getColor(this, R.color.dark_statusView))
mRelativeLayout?.setBackgroundColor(ContextCompat.getColor(this, R.color.dark_background)) mRelativeLayout?.setBackgroundColor(ContextCompat.getColor(this, R.color.dark_background))
@ -295,7 +30,7 @@ class BigChartWatchface : WatchFace() {
highColor = ContextCompat.getColor(this, R.color.dark_midColor) highColor = ContextCompat.getColor(this, R.color.dark_midColor)
lowColor = ContextCompat.getColor(this, R.color.dark_midColor) lowColor = ContextCompat.getColor(this, R.color.dark_midColor)
midColor = ContextCompat.getColor(this, R.color.dark_midColor) midColor = ContextCompat.getColor(this, R.color.dark_midColor)
gridColour = ContextCompat.getColor(this, R.color.dark_gridColor) gridColor = ContextCompat.getColor(this, R.color.dark_gridColor)
basalBackgroundColor = ContextCompat.getColor(this, R.color.basal_dark_lowres) basalBackgroundColor = ContextCompat.getColor(this, R.color.basal_dark_lowres)
basalCenterColor = ContextCompat.getColor(this, R.color.basal_light_lowres) basalCenterColor = ContextCompat.getColor(this, R.color.basal_light_lowres)
pointSize = 2 pointSize = 2
@ -303,7 +38,7 @@ class BigChartWatchface : WatchFace() {
} }
} }
private fun setColorDark() { override fun setColorDark() {
mTime?.setTextColor(ContextCompat.getColor(this, R.color.dark_mTime)) mTime?.setTextColor(ContextCompat.getColor(this, R.color.dark_mTime))
mStatus?.setTextColor(ContextCompat.getColor(this, R.color.dark_statusView)) mStatus?.setTextColor(ContextCompat.getColor(this, R.color.dark_statusView))
mRelativeLayout?.setBackgroundColor(ContextCompat.getColor(this, R.color.dark_background)) mRelativeLayout?.setBackgroundColor(ContextCompat.getColor(this, R.color.dark_background))
@ -335,7 +70,7 @@ class BigChartWatchface : WatchFace() {
highColor = ContextCompat.getColor(this, R.color.dark_highColor) highColor = ContextCompat.getColor(this, R.color.dark_highColor)
lowColor = ContextCompat.getColor(this, R.color.dark_lowColor) lowColor = ContextCompat.getColor(this, R.color.dark_lowColor)
midColor = ContextCompat.getColor(this, R.color.dark_midColor) midColor = ContextCompat.getColor(this, R.color.dark_midColor)
gridColour = ContextCompat.getColor(this, R.color.dark_gridColor) gridColor = ContextCompat.getColor(this, R.color.dark_gridColor)
basalBackgroundColor = ContextCompat.getColor(this, R.color.basal_dark) basalBackgroundColor = ContextCompat.getColor(this, R.color.basal_dark)
basalCenterColor = ContextCompat.getColor(this, R.color.basal_light) basalCenterColor = ContextCompat.getColor(this, R.color.basal_light)
pointSize = 2 pointSize = 2
@ -343,7 +78,7 @@ class BigChartWatchface : WatchFace() {
} }
} }
private fun setColorBright() { override fun setColorBright() {
if (currentWatchMode == WatchMode.INTERACTIVE) { if (currentWatchMode == WatchMode.INTERACTIVE) {
mTime?.setTextColor(ContextCompat.getColor(this, R.color.light_bigchart_time)) mTime?.setTextColor(ContextCompat.getColor(this, R.color.light_bigchart_time))
mStatus?.setTextColor(ContextCompat.getColor(this, R.color.light_bigchart_status)) mStatus?.setTextColor(ContextCompat.getColor(this, R.color.light_bigchart_status))
@ -373,7 +108,7 @@ class BigChartWatchface : WatchFace() {
highColor = ContextCompat.getColor(this, R.color.light_highColor) highColor = ContextCompat.getColor(this, R.color.light_highColor)
lowColor = ContextCompat.getColor(this, R.color.light_lowColor) lowColor = ContextCompat.getColor(this, R.color.light_lowColor)
midColor = ContextCompat.getColor(this, R.color.light_midColor) midColor = ContextCompat.getColor(this, R.color.light_midColor)
gridColour = ContextCompat.getColor(this, R.color.light_gridColor) gridColor = ContextCompat.getColor(this, R.color.light_gridColor)
basalBackgroundColor = ContextCompat.getColor(this, R.color.basal_light) basalBackgroundColor = ContextCompat.getColor(this, R.color.basal_light)
basalCenterColor = ContextCompat.getColor(this, R.color.basal_dark) basalCenterColor = ContextCompat.getColor(this, R.color.basal_dark)
pointSize = 2 pointSize = 2
@ -383,42 +118,4 @@ class BigChartWatchface : WatchFace() {
setColorDark() setColorDark()
} }
} }
private fun missedReadingAlert() {
val minutesSince = floor(timeSince() / (1000 * 60)).toInt()
if (minutesSince >= 16 && (minutesSince - 16) % 5 == 0) {
// attempt endTime recover missing data
rxBus.send(EventWearToMobile(ActionResendData("BIGChart:missedReadingAlert")))
}
}
private fun addToWatchSet() {
bgDataList = graphData.entries
}
private fun setupCharts() {
if (bgDataList.size > 0) {
val timeframe = sp.getInt(R.string.key_chart_time_frame, 3)
val bgGraphBuilder = if (lowResMode) {
BgGraphBuilder(
sp, dateUtil, bgDataList, treatmentData.predictions, treatmentData.temps, treatmentData.basals, treatmentData.boluses, pointSize,
midColor, gridColour, basalBackgroundColor, basalCenterColor, bolusColor, carbsColor, timeframe
)
} else {
BgGraphBuilder(
sp, dateUtil, bgDataList, treatmentData.predictions, treatmentData.temps, treatmentData.basals, treatmentData.boluses, pointSize,
highColor, lowColor, midColor, gridColour, basalBackgroundColor, basalCenterColor, bolusColor, carbsColor, timeframe
)
}
chart?.lineChartData = bgGraphBuilder.lineData()
chart?.isViewportCalculationEnabled = true
} else {
rxBus.send(EventWearToMobile(ActionResendData("BIGChart:setupCharts")))
}
}
companion object {
private const val SCREEN_SIZE_SMALL = 280
}
} }