321 lines
No EOL
14 KiB
Kotlin
321 lines
No EOL
14 KiB
Kotlin
@file:Suppress("DEPRECATION")
|
|
|
|
package info.nightscout.androidaps.watchfaces
|
|
|
|
import android.annotation.SuppressLint
|
|
import android.content.Intent
|
|
import android.graphics.Canvas
|
|
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 com.ustwo.clockwise.common.WatchFaceTime
|
|
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.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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
|
import javax.inject.Inject
|
|
import kotlin.math.floor
|
|
|
|
class NoChartWatchface : WatchFace() {
|
|
|
|
@Inject lateinit var rxBus: RxBus
|
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
|
@Inject lateinit var aapsLogger: AAPSLogger
|
|
@Inject lateinit var sp: SP
|
|
@Inject lateinit var dateUtil: DateUtil
|
|
|
|
private var disposable = CompositeDisposable()
|
|
|
|
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 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 sgvLevel: Long = 0
|
|
private var ageLevel = 1
|
|
private var lowResMode = false
|
|
private var layoutSet = false
|
|
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 statusView: TextView? = null
|
|
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:NOChart")
|
|
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_nochart_small, null)
|
|
} else {
|
|
inflater.inflate(R.layout.activity_nochart, null)
|
|
}
|
|
disposable += rxBus
|
|
.toObservable(SingleBg::class.java)
|
|
.observeOn(aapsSchedulers.main)
|
|
.subscribe { event: SingleBg ->
|
|
aapsLogger.debug(LTag.WEAR, "SingleBg received")
|
|
singleBg = event
|
|
mSgv?.let { sgv ->
|
|
sgv.text = singleBg.sgvString
|
|
if (ageLevel() <= 0) sgv.paintFlags = sgv.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
|
else sgv.paintFlags = sgv.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
|
}
|
|
mTime?.text = dateUtil.timeString()
|
|
mDelta?.text = singleBg.delta
|
|
mAvgDelta?.text = singleBg.avgDelta
|
|
}
|
|
disposable += rxBus
|
|
.toObservable(EventData.Status::class.java)
|
|
.observeOn(aapsSchedulers.main)
|
|
.subscribe { event: EventData.Status ->
|
|
// this event is received as last batch of data
|
|
aapsLogger.debug(LTag.WEAR, "Status received")
|
|
status = event
|
|
showAgeAndStatus()
|
|
mRelativeLayout?.measure(specW, specH)
|
|
mRelativeLayout?.layout(0, 0, mRelativeLayout?.measuredWidth ?: 0, mRelativeLayout?.measuredHeight ?: 0)
|
|
invalidate()
|
|
setColor()
|
|
}
|
|
disposable += 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()
|
|
}
|
|
performViewSetup()
|
|
}
|
|
|
|
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)
|
|
statusView = layoutView?.findViewById(R.id.aps_status)
|
|
layoutSet = true
|
|
showAgeAndStatus()
|
|
mRelativeLayout?.measure(specW, specH)
|
|
mRelativeLayout?.layout(0, 0, mRelativeLayout?.measuredWidth ?: 0, mRelativeLayout?.measuredHeight ?: 0)
|
|
rxBus.send(EventWearToMobile(ActionResendData("NOChart:performViewSetup")))
|
|
}
|
|
|
|
override fun onTapCommand(tapType: Int, x: Int, y: Int, eventTime: Long) {
|
|
mSgv?.let { mSgv ->
|
|
val extra = (mSgv.right - mSgv.left) / 2
|
|
if (tapType == TAP_TYPE_TAP && x + extra >= mSgv.left && x - extra <= mSgv.right && y >= mSgv.top && y <= mSgv.bottom) {
|
|
if (eventTime - sgvTapTime < 800) {
|
|
startActivity(Intent(this, MainMenuActivity::class.java).also { it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
|
}
|
|
sgvTapTime = eventTime
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = if (timeSince() <= 1000 * 60 * 12) 1 else 0
|
|
|
|
fun timeSince(): Double = (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))) {
|
|
mTime?.text = dateUtil.timeString()
|
|
showAgeAndStatus()
|
|
mSgv?.let { sgv ->
|
|
if (ageLevel() <= 0) {
|
|
sgv.paintFlags = sgv.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
|
} else {
|
|
sgv.paintFlags = sgv.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_avg_delta, true).toVisibility()
|
|
statusView?.text = status.externalStatus
|
|
statusView?.visibility = View.VISIBLE
|
|
}
|
|
|
|
private fun setColor() {
|
|
when {
|
|
lowResMode -> setColorLowRes()
|
|
sp.getBoolean("dark", true) -> setColorDark()
|
|
else -> setColorBright()
|
|
}
|
|
}
|
|
|
|
private fun setColorLowRes() {
|
|
mTime?.setTextColor(ContextCompat.getColor(this, R.color.dark_mTime))
|
|
statusView?.setTextColor(ContextCompat.getColor(this, R.color.dark_statusView))
|
|
mRelativeLayout?.setBackgroundColor(ContextCompat.getColor(this, R.color.dark_background))
|
|
mSgv?.setTextColor(ContextCompat.getColor(this, R.color.dark_midColor))
|
|
mDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_midColor))
|
|
mAvgDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_midColor))
|
|
mTimestamp?.setTextColor(ContextCompat.getColor(this, R.color.dark_Timestamp))
|
|
}
|
|
|
|
private fun setColorDark() {
|
|
mTime?.setTextColor(ContextCompat.getColor(this, R.color.dark_mTime))
|
|
statusView?.setTextColor(ContextCompat.getColor(this, R.color.dark_statusView))
|
|
mRelativeLayout?.setBackgroundColor(ContextCompat.getColor(this, R.color.dark_background))
|
|
when (sgvLevel) {
|
|
1L -> {
|
|
mSgv?.setTextColor(ContextCompat.getColor(this, R.color.dark_highColor))
|
|
mDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_highColor))
|
|
mAvgDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_highColor))
|
|
}
|
|
|
|
0L -> {
|
|
mSgv?.setTextColor(ContextCompat.getColor(this, R.color.dark_midColor))
|
|
mDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_midColor))
|
|
mAvgDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_midColor))
|
|
}
|
|
|
|
-1L -> {
|
|
mSgv?.setTextColor(ContextCompat.getColor(this, R.color.dark_lowColor))
|
|
mDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_lowColor))
|
|
mAvgDelta?.setTextColor(ContextCompat.getColor(this, R.color.dark_lowColor))
|
|
}
|
|
}
|
|
if (ageLevel == 1) {
|
|
mTimestamp?.setTextColor(ContextCompat.getColor(this, R.color.dark_Timestamp))
|
|
} else {
|
|
mTimestamp?.setTextColor(ContextCompat.getColor(this, R.color.dark_TimestampOld))
|
|
}
|
|
}
|
|
|
|
private fun setColorBright() {
|
|
if (currentWatchMode == WatchMode.INTERACTIVE) {
|
|
mTime?.setTextColor(ContextCompat.getColor(this, R.color.light_bigchart_time))
|
|
statusView?.setTextColor(ContextCompat.getColor(this, R.color.light_bigchart_status))
|
|
mRelativeLayout?.setBackgroundColor(ContextCompat.getColor(this, R.color.light_background))
|
|
when (sgvLevel) {
|
|
1L -> {
|
|
mSgv?.setTextColor(ContextCompat.getColor(this, R.color.light_highColor))
|
|
mDelta?.setTextColor(ContextCompat.getColor(this, R.color.light_highColor))
|
|
mAvgDelta?.setTextColor(ContextCompat.getColor(this, R.color.light_highColor))
|
|
}
|
|
|
|
0L -> {
|
|
mSgv?.setTextColor(ContextCompat.getColor(this, R.color.light_midColor))
|
|
mDelta?.setTextColor(ContextCompat.getColor(this, R.color.light_midColor))
|
|
mAvgDelta?.setTextColor(ContextCompat.getColor(this, R.color.light_midColor))
|
|
}
|
|
|
|
-1L -> {
|
|
mSgv?.setTextColor(ContextCompat.getColor(this, R.color.light_lowColor))
|
|
mDelta?.setTextColor(ContextCompat.getColor(this, R.color.light_lowColor))
|
|
mAvgDelta?.setTextColor(ContextCompat.getColor(this, R.color.light_lowColor))
|
|
}
|
|
}
|
|
if (ageLevel == 1) {
|
|
mTimestamp?.setTextColor(ContextCompat.getColor(this, R.color.light_mTimestamp1))
|
|
} else {
|
|
mTimestamp?.setTextColor(ContextCompat.getColor(this, R.color.light_mTimestamp))
|
|
}
|
|
} else {
|
|
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("NOChart::missedReadingAlert")))
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
|
|
const val SCREEN_SIZE_SMALL = 280
|
|
}
|
|
} |