Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wear: add Loop States tile #3725

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ sealed class EventData : Event() {
@Serializable
data class ActionUserActionConfirmed(val id: Int, val title: String) : EventData()

@Serializable
data class LoopStatesRequest(val timeStamp: Long) : EventData()

@Serializable
data class LoopStateSelected(val timeStamp: Long, val index: Int, val duration: Int? = null) : EventData()

@Serializable
data class LoopStateConfirmed(val timeStamp: Long, val index: Int, val duration: Int? = null) : EventData()

@Serializable
data class ActionHeartRate(
val duration: Long,
Expand Down Expand Up @@ -177,6 +186,37 @@ sealed class EventData : Event() {
@Serializable
data class OpenLoopRequestConfirmed(val timeStamp: Long) : EventData()

@Serializable
data class LoopStatesList(val timeStamp: Long, val states: List<AvailableLoopState>, val currentState: AvailableLoopState) : EventData() {
@Serializable
data class AvailableLoopState(
val state: LoopState,
val durations: List<Int>? = null,
val title: String? = null, // used for FAKE_DIVIDER
) {
@Serializable
enum class LoopState {
// See LoopDialog
LOOP_OPEN,
LOOP_LGS,
LOOP_CLOSED,

LOOP_DISABLE,
LOOP_ENABLE,

LOOP_SUSPEND, // 1h, 2h, 3h, 10h
LOOP_RESUME,

PUMP_DISCONNECT, // 15m, 30m, 1h, 2h, 3h
PUMP_RECONNECT,

// Returned current statuses
LOOP_UNKNOWN,
SUPERBOLUS,
}
}
}

// Mobile -> Wear
@Serializable
data class CancelNotification(val timeStamp: Long) : EventData()
Expand Down Expand Up @@ -366,4 +406,12 @@ sealed class EventData : Event() {

@Serializable
data class SnoozeAlert(val timeStamp: Long) : EventData()

// Wear -> Wear (workaround)
@Serializable
data class LoopStatePreSelect(
val timeStamp: Long,
val stateIndex: Int,
val durations: List<Int>
) : EventData()
}

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions plugins/sync/src/main/res/values-ru-rRU/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,27 @@
<string name="today">Сегодня</string>
<string name="weighted">взвешенный</string>
<string name="full_xdrip_sync_comment">Полная синхронизация? Это может занять длительное время и до завершения вы не увидите новые данные в xDrip+.</string>

<string name="wear_action_loop_state_no_nsclient">AAPSClient не поддерживается для этого действия</string>
<string name="wear_action_loop_state_requires_duration">Это действие требует продолжительности</string>
<string name="wear_action_loop_state_pump_suspended">Помпа приостановлена!</string>
<string name="wear_action_loop_state_profile_invalid">Неверный профиль!</string>
<string name="wear_action_loop_state_unauthorized">Повторите попытку.</string>
<string name="wear_action_loop_state_invalid">Запрошен неверный тип цикла</string>

<string name="wear_action_loop_state_title">СОСТ. ЦИКЛА</string>
<string name="wear_action_loop_state_changed">%1$s</string>
<string name="wear_action_loop_state_changed_with_duration">%1$s\nДлительность: %2$d мин</string>

<string name="wear_action_loop_state_now_closed">Закрытый</string>
<string name="wear_action_loop_state_now_lgs">LGS</string>
<string name="wear_action_loop_state_now_open">Открытый</string>
<string name="wear_action_loop_state_now_suspended">Приостановлен</string>
<string name="wear_action_loop_state_now_resumed">Возобновлен</string>
<string name="wear_action_loop_state_now_disabled">Отключен</string>
<string name="wear_action_loop_state_now_enabled">Включен</string>
<string name="wear_action_loop_state_now_superbolus">Суперболюс</string>
<string name="wear_action_loop_state_now_invalid">Неизвестно</string>
<string name="wear_action_loop_state_now_pump_disconnected">Помпа отключена</string>
<string name="wear_action_loop_state_now_pump_reconnected">Помпа подключена</string>
</resources>
23 changes: 23 additions & 0 deletions plugins/sync/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,27 @@
<string name="weighted">weighted</string>
<string name="full_xdrip_sync_comment">Full synchronization? It may take a while and until it is finished you\'ll not see new data in xDrip+.</string>

<string name="wear_action_loop_state_no_nsclient">AAPSClient is not supported for this action</string>
<string name="wear_action_loop_state_requires_duration">This action requires duration</string>
<string name="wear_action_loop_state_pump_suspended">Pump is suspended!</string>
<string name="wear_action_loop_state_profile_invalid">Profile is invalid!</string>
<string name="wear_action_loop_state_unauthorized">Please try again.</string>
<string name="wear_action_loop_state_invalid">Invalid loop state requested</string>

<string name="wear_action_loop_state_title">LOOP STATE</string>
<string name="wear_action_loop_state_changed">%1$s</string>
<string name="wear_action_loop_state_changed_with_duration">%1$s\nDuration: %2$d min</string>

<string name="wear_action_loop_state_now_closed">Closed</string>
<string name="wear_action_loop_state_now_lgs">LGS</string>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's plenty of space for text in the wear tile confirmation box I would use Low glucose suspend instead of LGS

<string name="wear_action_loop_state_now_open">Open</string>
<string name="wear_action_loop_state_now_suspended">Suspended</string>
<string name="wear_action_loop_state_now_resumed">Resumed</string>
<string name="wear_action_loop_state_now_disabled">Disabled</string>
<string name="wear_action_loop_state_now_enabled">Enabled</string>
<string name="wear_action_loop_state_now_superbolus">Superbolus</string>
<string name="wear_action_loop_state_now_invalid">Invalid</string>
<string name="wear_action_loop_state_now_pump_disconnected">Pump disconnected</string>
<string name="wear_action_loop_state_now_pump_reconnected">Pump reconnected</string>

</resources>
18 changes: 18 additions & 0 deletions wear/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,20 @@
android:resource="@drawable/user_action_tiles" />
</service>

<service
android:name=".tile.LoopStateTileService"
android:exported="true"
android:label="@string/label_loop_state_title"
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
<intent-filter>
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
</intent-filter>

<meta-data
android:name="androidx.wear.tiles.PREVIEW"
android:resource="@drawable/loop_states_tile" />
</service>

<receiver android:name=".complications.ComplicationTapBroadcastReceiver" />

<activity
Expand Down Expand Up @@ -525,6 +539,10 @@
android:name=".interaction.actions.BackgroundActionActivity"
android:exported="true" />

<activity
android:name=".interaction.actions.LoopStateTimedActivity"
android:exported="true" />

<activity
android:name=".interaction.ConfigurationActivity"
android:exported="true">
Expand Down
12 changes: 12 additions & 0 deletions wear/src/main/kotlin/app/aaps/wear/comm/DataHandlerWear.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import app.aaps.wear.interaction.actions.AcceptActivity
import app.aaps.wear.interaction.actions.ProfileSwitchActivity
import app.aaps.wear.interaction.utils.Persistence
import app.aaps.wear.tile.ActionsTileService
import app.aaps.wear.tile.LoopStateTileService
import app.aaps.wear.tile.QuickWizardTileService
import app.aaps.wear.tile.TempTargetTileService
import app.aaps.wear.tile.UserActionTileService
Expand Down Expand Up @@ -193,6 +194,17 @@ class DataHandlerWear @Inject constructor(
TileService.getUpdater(context).requestUpdate(UserActionTileService::class.java)
}
}
disposable += rxBus
.toObservable(EventData.LoopStatesList::class.java)
.observeOn(aapsSchedulers.io)
.subscribe {
aapsLogger.debug(LTag.WEAR, "Loop states received from ${it.sourceNodeId}")
val serialized = it.serialize()
if (serialized != sp.getString(R.string.key_loop_states_data, "")) {
sp.putString(R.string.key_loop_states_data, serialized)
TileService.getUpdater(context).requestUpdate(LoopStateTileService::class.java)
}
}
disposable += rxBus
.toObservable(EventData.ActionSetCustomWatchface::class.java)
.observeOn(aapsSchedulers.io)
Expand Down
2 changes: 2 additions & 0 deletions wear/src/main/kotlin/app/aaps/wear/di/WearActivitiesModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import app.aaps.wear.interaction.actions.BolusActivity
import app.aaps.wear.interaction.actions.CarbActivity
import app.aaps.wear.interaction.actions.ECarbActivity
import app.aaps.wear.interaction.actions.FillActivity
import app.aaps.wear.interaction.actions.LoopStateTimedActivity
import app.aaps.wear.interaction.actions.ProfileSwitchActivity
import app.aaps.wear.interaction.actions.QuickSnoozeActivity
import app.aaps.wear.interaction.actions.TempTargetActivity
Expand Down Expand Up @@ -48,4 +49,5 @@ abstract class WearActivitiesModule {
@ContributesAndroidInjector abstract fun contributesMainMenuActivity(): MainMenuActivity
@ContributesAndroidInjector abstract fun contributesStatusMenuActivity(): StatusMenuActivity
@ContributesAndroidInjector abstract fun contributesQuickSnoozeActivity(): QuickSnoozeActivity
@ContributesAndroidInjector abstract fun contributesLoopStateTimedActivity(): LoopStateTimedActivity
}
2 changes: 2 additions & 0 deletions wear/src/main/kotlin/app/aaps/wear/di/WearServicesModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import app.aaps.wear.complications.UploaderBatteryComplication
import app.aaps.wear.complications.WallpaperComplication
import app.aaps.wear.heartrate.HeartRateListener
import app.aaps.wear.tile.ActionsTileService
import app.aaps.wear.tile.LoopStateTileService
import app.aaps.wear.tile.QuickWizardTileService
import app.aaps.wear.tile.TempTargetTileService
import app.aaps.wear.tile.TileBase
Expand Down Expand Up @@ -61,5 +62,6 @@ abstract class WearServicesModule {
@ContributesAndroidInjector abstract fun contributesUserActionTileService(): UserActionTileService
@ContributesAndroidInjector abstract fun contributesTempTargetTileService(): TempTargetTileService
@ContributesAndroidInjector abstract fun contributesActionsTileService(): ActionsTileService
@ContributesAndroidInjector abstract fun contributesLoopStateTileService(): LoopStateTileService

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package app.aaps.wear.interaction.actions

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import app.aaps.core.interfaces.logging.AAPSLogger
import app.aaps.core.interfaces.logging.LTag
import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.EventWearToMobile
import app.aaps.core.interfaces.rx.weardata.EventData
import app.aaps.core.interfaces.rx.weardata.EventData.ActionBolusPreCheck
import app.aaps.core.interfaces.utils.SafeParse
import app.aaps.core.keys.DoubleKey
import app.aaps.wear.R
import app.aaps.wear.comm.DataLayerListenerServiceWear
import app.aaps.wear.interaction.utils.EditPlusMinusViewAdapter
import app.aaps.wear.interaction.utils.PlusMinusEditText
import app.aaps.wear.nondeprecated.GridPagerAdapterNonDeprecated
import java.text.DecimalFormat
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.roundToInt

class LoopStateTimedActivity : ViewSelectorActivity() {
@Inject lateinit var aapsLogger: AAPSLogger
var editDuration: PlusMinusEditText? = null
var eventData: EventData.LoopStatePreSelect? = null
var isHours = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent.extras?.getString(DataLayerListenerServiceWear.KEY_ACTION)?.let { action ->
aapsLogger.info(LTag.WEAR, "LoopStateTimedActivity.onCreate: action=$action")
eventData = EventData.deserialize(action) as EventData.LoopStatePreSelect
} ?: aapsLogger.error(LTag.WEAR, "LoopStateTimedActivity.onCreate extras 'actionString' required")
setAdapter(MyGridViewPagerAdapter())
}

override fun onPause() {
super.onPause()
finish()
}

private inner class MyGridViewPagerAdapter : GridPagerAdapterNonDeprecated() {

override fun getColumnCount(arg0: Int): Int = 2
override fun getRowCount(): Int = 1

override fun instantiateItem(container: ViewGroup, row: Int, col: Int): View = when (col) {
0 -> {
val viewAdapter = EditPlusMinusViewAdapter.getViewAdapter(sp, applicationContext, container, true)
val minValue = (eventData!!.durations.firstOrNull() ?: 60).let {
if (it >= 60) {
isHours = true
it / 60
} else it
}
val maxValue = (eventData!!.durations.lastOrNull() ?: 240).let {
if (isHours) it / 60 else it
}

val title = if (isHours)
getString(R.string.action_duration_h)
else
getString(R.string.action_duration)
editDuration = PlusMinusEditText(
viewAdapter,
minValue.toDouble(), minValue.toDouble(),
maxValue.toDouble(),
when (minValue) {
30 -> listOf(30.0, 60.0, 90.0)
15 -> listOf(15.0, 30.0, 45.0)
else -> listOf(1.0, 2.0, 3.0)
},
DecimalFormat("0"), false, title)

val view = viewAdapter.root
container.addView(view)
view.requestFocus()
view
}

else -> {
val view = LayoutInflater.from(applicationContext).inflate(R.layout.action_confirm_ok, container, false)
val confirmButton = view.findViewById<ImageView>(R.id.confirmbutton)
confirmButton.setOnClickListener {
rxBus.send(EventWearToMobile(
EventData.LoopStateSelected(
eventData!!.timeStamp,
eventData!!.stateIndex,
SafeParse.stringToDouble(editDuration?.editText?.text.toString()).toInt().let {
if (isHours) it * 60 else it
}
)
))
showToast(this@LoopStateTimedActivity, R.string.action_loop_state_selected)
finishAffinity()
}
container.addView(view)
view
}
}

override fun destroyItem(container: ViewGroup, row: Int, col: Int, view: Any) {
container.removeView(view as View)
}

override fun isViewFromObject(view: View, `object`: Any): Boolean = view === `object`
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ open class Persistence @Inject constructor(
const val STATUS_PERSISTENCE_KEY = "status_data"
const val STATUS1_PERSISTENCE_KEY = "status1_data"
const val STATUS2_PERSISTENCE_KEY = "status2_data"
const val LOOP_STATES_PERSISTENCE_KEY = "loop_states"

const val KEY_COMPLICATIONS = "complications"
const val KEY_LAST_SHOWN_SINCE_VALUE = "lastSince"
Expand Down Expand Up @@ -234,6 +235,11 @@ open class Persistence @Inject constructor(
aapsLogger.debug(LTag.WEAR, "Stored Treatments data: $treatmentData")
}

fun store(states: EventData.LoopStatesList) {
putString(LOOP_STATES_PERSISTENCE_KEY, states.serialize())
aapsLogger.debug(LTag.WEAR, "Stored Loop states data: $states")
}

fun store(status: EventData.Status) {
when (status.dataset) {
0 -> {
Expand Down
21 changes: 21 additions & 0 deletions wear/src/main/kotlin/app/aaps/wear/tile/LoopStateTileService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package app.aaps.wear.tile

import app.aaps.wear.tile.source.LoopStateSource
import dagger.android.AndroidInjection
import javax.inject.Inject

class LoopStateTileService : TileBase() {

@Inject lateinit var loopStateSource: LoopStateSource

// Not derived from DaggerService, do injection here
override fun onCreate() {
AndroidInjection.inject(this)
super.onCreate()
}

override val resourceVersion = "LoopStateTileService"
override val source get() = loopStateSource
}


Loading