More Wear OS work

This commit is contained in:
2021-09-07 21:52:33 -04:00
parent 1f5e5bca3a
commit 1f2c059e9c
10 changed files with 254 additions and 17 deletions

View File

@@ -5,6 +5,7 @@ import android.os.Bundle
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.wear.tiles.manager.TileUiClient import androidx.wear.tiles.manager.TileUiClient
import com.chriskaczor.homemonitor.wear.power.PowerTileService
class TilePreviewActivity : ComponentActivity() { class TilePreviewActivity : ComponentActivity() {
lateinit var tileUiClient: TileUiClient lateinit var tileUiClient: TileUiClient

View File

@@ -18,9 +18,9 @@
android:value="true" /> android:value="true" />
<service <service
android:name="com.chriskaczor.homemonitor.wear.PowerTileService" android:name="com.chriskaczor.homemonitor.wear.power.PowerTileService"
android:description="@string/tile_description" android:description="@string/tile_description"
android:icon="@drawable/ic_refresh" android:icon="@drawable/ic_plug"
android:label="@string/power_tile_label" android:label="@string/power_tile_label"
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"> android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
<intent-filter> <intent-filter>
@@ -29,7 +29,22 @@
<meta-data <meta-data
android:name="androidx.wear.tiles.PREVIEW" android:name="androidx.wear.tiles.PREVIEW"
android:resource="@drawable/tile_goals" /> android:resource="@drawable/tile_power" />
</service>
<service
android:name="com.chriskaczor.homemonitor.wear.weather.WeatherTileService"
android:description="@string/tile_description"
android:icon="@drawable/ic_sun"
android:label="@string/weather_tile_label"
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/tile_weather" />
</service> </service>
</application> </application>
</manifest> </manifest>

View File

@@ -1,4 +1,4 @@
package com.chriskaczor.homemonitor.wear package com.chriskaczor.homemonitor.wear.power
import com.beust.klaxon.Json import com.beust.klaxon.Json
import com.beust.klaxon.Klaxon import com.beust.klaxon.Klaxon
@@ -17,16 +17,11 @@ data class PowerStatus(
) )
object PowerRepository { object PowerRepository {
suspend fun getPowerStatus(): PowerStatus { suspend fun getPowerStatus(): PowerStatus? {
val json = URL("http://home.kaczorzoo.net/api/power/status/recent").readText(); val json = URL("http://home.kaczorzoo.net/api/power/status/recent").readText();
val data = Klaxon().parse<PowerStatus>(json) ?: return powerStatus; val powerStatus = Klaxon().parse<PowerStatus>(json);
powerStatus = powerStatus.copy(generation = data.generation, consumption = data.consumption, timestamp = data.timestamp);
return powerStatus; return powerStatus;
} }
} }
var powerStatus =
PowerStatus(generation = 0, consumption = 0, timestamp = Timestamp(System.currentTimeMillis()).toString())

View File

@@ -1,4 +1,4 @@
package com.chriskaczor.homemonitor.wear package com.chriskaczor.homemonitor.wear.power
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.wear.tiles.ActionBuilders import androidx.wear.tiles.ActionBuilders
@@ -15,6 +15,7 @@ import androidx.wear.tiles.TileBuilders.Tile
import androidx.wear.tiles.TileService import androidx.wear.tiles.TileService
import androidx.wear.tiles.TimelineBuilders.Timeline import androidx.wear.tiles.TimelineBuilders.Timeline
import androidx.wear.tiles.TimelineBuilders.TimelineEntry import androidx.wear.tiles.TimelineBuilders.TimelineEntry
import com.chriskaczor.homemonitor.wear.R
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
@@ -95,17 +96,17 @@ class PowerTileService : TileService() {
serviceScope.cancel() serviceScope.cancel()
} }
private fun layout(goalProgress: PowerStatus, deviceParameters: DeviceParameters) = private fun layout(goalProgress: PowerStatus?, deviceParameters: DeviceParameters) =
Box.Builder() Box.Builder()
.setWidth(expand()) .setWidth(expand())
.setHeight(expand()) .setHeight(expand())
.addContent( .addContent(
Column.Builder() Column.Builder()
.addContent( .addContent(
generationLayout(goalProgress.generation, deviceParameters) generationLayout(goalProgress?.generation ?: -1, deviceParameters)
) )
.addContent( .addContent(
consumptionLayout(goalProgress.consumption, deviceParameters) consumptionLayout(goalProgress?.consumption ?: -1, deviceParameters)
) )
.addContent(Spacer.Builder().setHeight(VERTICAL_SPACING_HEIGHT).build()) .addContent(Spacer.Builder().setHeight(VERTICAL_SPACING_HEIGHT).build())
.addContent(refreshButton()) .addContent(refreshButton())
@@ -135,7 +136,7 @@ class PowerTileService : TileService() {
) )
.addContent( .addContent(
Text.Builder() Text.Builder()
.setText(generation.toString()) .setText(if (generation <= 0) "0" else generation.toString())
.setFontStyle(FontStyles.display3(deviceParameters).build()) .setFontStyle(FontStyles.display3(deviceParameters).build())
.build() .build()
).build() ).build()
@@ -163,7 +164,7 @@ class PowerTileService : TileService() {
) )
.addContent( .addContent(
Text.Builder() Text.Builder()
.setText(consumption.toString()) .setText(if (consumption <= 0) "0" else consumption.toString())
.setFontStyle(FontStyles.display3(deviceParameters).build()) .setFontStyle(FontStyles.display3(deviceParameters).build())
.build() .build()
).build() ).build()

View File

@@ -0,0 +1,24 @@
package com.chriskaczor.homemonitor.wear.weather
import com.beust.klaxon.Json
import com.beust.klaxon.Klaxon
import java.net.URL
import java.sql.Timestamp
data class WeatherStatus(
@Json(name = "humidity")
val humidity: Double,
@Json(name = "pressure")
val pressure: Double,
)
object WeatherRepository {
suspend fun getWeatherStatus(): WeatherStatus? {
var json = URL("http://home.kaczorzoo.net/api/weather/readings/recent").readText();
var weatherStatus = Klaxon().parse<WeatherStatus>(json);
return weatherStatus;
}
}

View File

@@ -0,0 +1,200 @@
package com.chriskaczor.homemonitor.wear.weather
import androidx.core.content.ContextCompat
import androidx.wear.tiles.ActionBuilders
import androidx.wear.tiles.ColorBuilders.argb
import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters
import androidx.wear.tiles.DimensionBuilders.dp
import androidx.wear.tiles.DimensionBuilders.expand
import androidx.wear.tiles.LayoutElementBuilders.*
import androidx.wear.tiles.ModifiersBuilders.*
import androidx.wear.tiles.RequestBuilders.ResourcesRequest
import androidx.wear.tiles.RequestBuilders.TileRequest
import androidx.wear.tiles.ResourceBuilders.*
import androidx.wear.tiles.TileBuilders.Tile
import androidx.wear.tiles.TileService
import androidx.wear.tiles.TimelineBuilders.Timeline
import androidx.wear.tiles.TimelineBuilders.TimelineEntry
import com.chriskaczor.homemonitor.wear.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.guava.future
private const val RESOURCES_VERSION = "1"
// dimensions
private val BUTTON_SIZE = dp(48f)
private val BUTTON_RADIUS = dp(24f)
private val BUTTON_PADDING = dp(12f)
private val VERTICAL_SPACING_HEIGHT = dp(8f)
// identifiers
private const val ID_IMAGE_REFRESH = "image_refresh"
private const val ID_IMAGE_GENERATION = "image_generation"
private const val ID_IMAGE_CONSUMPTION = "image_consumption"
private const val ID_CLICK_REFRESH = "click_refresh"
class WeatherTileService : TileService() {
private val serviceScope = CoroutineScope(Dispatchers.IO)
override fun onTileRequest(requestParams: TileRequest) = serviceScope.future {
val powerStatus = WeatherRepository.getWeatherStatus()
val deviceParams = requestParams.deviceParameters!!
Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTimeline(
Timeline.Builder()
.addTimelineEntry(
TimelineEntry.Builder()
.setLayout(
Layout.Builder()
.setRoot(
layout(powerStatus, deviceParams)
).build()
).build()
).build()
).build()
}
override fun onResourcesRequest(requestParams: ResourcesRequest) = serviceScope.future {
Resources.Builder()
.setVersion(RESOURCES_VERSION)
.addIdToImageMapping(
ID_IMAGE_REFRESH,
ImageResource.Builder()
.setAndroidResourceByResId(
AndroidImageResourceByResId.Builder()
.setResourceId(R.drawable.ic_refresh)
.build()
).build()
)
.addIdToImageMapping(
ID_IMAGE_GENERATION,
ImageResource.Builder()
.setAndroidResourceByResId(
AndroidImageResourceByResId.Builder()
.setResourceId(R.drawable.ic_sun)
.build()
).build()
)
.addIdToImageMapping(
ID_IMAGE_CONSUMPTION,
ImageResource.Builder()
.setAndroidResourceByResId(
AndroidImageResourceByResId.Builder()
.setResourceId(R.drawable.ic_plug)
.build()
).build()
).build()
}
override fun onDestroy() {
super.onDestroy()
serviceScope.cancel()
}
private fun layout(goalProgress: WeatherStatus?, deviceParameters: DeviceParameters) =
Box.Builder()
.setWidth(expand())
.setHeight(expand())
.addContent(
Column.Builder()
.addContent(
generationLayout(goalProgress?.humidity ?: -1.0, deviceParameters)
)
.addContent(
consumptionLayout(goalProgress?.pressure ?: -1.0, deviceParameters)
)
.addContent(Spacer.Builder().setHeight(VERTICAL_SPACING_HEIGHT).build())
.addContent(refreshButton())
.build()
).build()
private fun generationLayout(generation: Double, deviceParameters: DeviceParameters) =
Row.Builder()
.addContent(
Image.Builder()
.setHeight(dp(36f))
.setWidth(dp(36f))
.setModifiers(
Modifiers.Builder()
.setPadding(
Padding.Builder()
.setStart(dp(0f))
.setEnd(dp(10f))
.setTop(dp(1f))
.setBottom(dp(0f))
.build()
)
.build()
)
.setResourceId(ID_IMAGE_GENERATION)
.build()
)
.addContent(
Text.Builder()
.setText(if (generation <= 0) "0" else generation.toString())
.setFontStyle(FontStyles.display3(deviceParameters).build())
.build()
).build()
private fun consumptionLayout(consumption: Double, deviceParameters: DeviceParameters) =
Row.Builder()
.addContent(
Image.Builder()
.setHeight(dp(36f))
.setWidth(dp(36f))
.setModifiers(
Modifiers.Builder()
.setPadding(
Padding.Builder()
.setStart(dp(0f))
.setEnd(dp(10f))
.setTop(dp(1f))
.setBottom(dp(0f))
.build()
)
.build()
)
.setResourceId(ID_IMAGE_CONSUMPTION)
.build()
)
.addContent(
Text.Builder()
.setText(if (consumption <= 0) "0" else consumption.toString())
.setFontStyle(FontStyles.display3(deviceParameters).build())
.build()
).build()
private fun refreshButton() =
Image.Builder()
.setWidth(BUTTON_SIZE)
.setHeight(BUTTON_SIZE)
.setResourceId(ID_IMAGE_REFRESH)
.setModifiers(
Modifiers.Builder()
.setPadding(
Padding.Builder()
.setStart(BUTTON_PADDING)
.setEnd(BUTTON_PADDING)
.setTop(BUTTON_PADDING)
.setBottom(BUTTON_PADDING)
.build()
)
.setBackground(
Background.Builder()
.setCorner(Corner.Builder().setRadius(BUTTON_RADIUS).build())
.setColor(argb(ContextCompat.getColor(this, R.color.primaryDark)))
.build()
)
.setClickable(
Clickable.Builder()
.setId(ID_CLICK_REFRESH)
.setOnClick(ActionBuilders.LoadAction.Builder().build())
.build()
).build()
).build()
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -4,4 +4,5 @@
<string name="tile_description">Home Monitor</string> <string name="tile_description">Home Monitor</string>
<string name="power_tile_label">Power</string> <string name="power_tile_label">Power</string>
<string name="weather_tile_label">Weather</string>
</resources> </resources>