Skip to content

Commit

Permalink
Add logged out state to Wear tiles (#3440)
Browse files Browse the repository at this point in the history
- Adds a generic tile to be used when the Wear app isn't logged in
 - Simplify tile root layout building using Timeline.fromLayoutElement
  • Loading branch information
jpelgrom committed Apr 1, 2023
1 parent b6688c6 commit cc20ffe
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 45 deletions.
5 changes: 4 additions & 1 deletion common/src/main/res/values/strings.xml
Expand Up @@ -708,6 +708,7 @@
<string name="shortcuts_tile_description">Select up to 7 entities</string>
<string name="shortcuts_tile_empty">Choose entities in settings</string>
<string name="shortcuts_tile_text_setting">Show names on shortcuts tile</string>
<string name="shortcuts_tile_log_in">Log in to Home Assistant to add your first shortcut</string>
<string name="shortcuts">Shortcuts</string>
<string name="show">Show</string>
<string name="show_share_logs_summary">Sharing logs with the Home Assistant team will help to solve issues. Please share the logs only if you have been asked to do so by a Home Assistant developer</string>
Expand Down Expand Up @@ -764,6 +765,7 @@
<string name="template_tile_content">Template tile content</string>
<string name="template_tile_desc">Renders and displays a template</string>
<string name="template_tile_empty">Set template in the phone settings</string>
<string name="template_tile_log_in">Log in to Home Assistant to set up a template</string>
<string name="template_error">Error in template</string>
<string name="template_render_error">Error rendering template</string>
<string name="template_tile_help">Provide a template below that will be displayed on the Wear OS template tile. See help for markup options.</string>
Expand Down Expand Up @@ -1045,7 +1047,8 @@
<string name="no_conversation_support">You must be at least on Home Assistant 2023.1 and have the conversation integration enabled</string>
<string name="conversation">Conversation</string>
<string name="assist">Assist</string>
<string name="not_registered">Please launch the Home Assistant app and login before you can use the assist feature.</string>
<string name="assist_log_in">Log in to Home Assistant to start using Assist</string>
<string name="not_registered">Please launch the Home Assistant app and log in to start using Assist.</string>
<string name="ha_assist">HA: Assist</string>
<string name="only_favorites">Only Show Favorites</string>
<string name="beacon_scanning">Beacon Monitor Scanning</string>
Expand Down
1 change: 1 addition & 0 deletions wear/build.gradle.kts
Expand Up @@ -124,6 +124,7 @@ dependencies {

implementation("com.google.guava:guava:31.1-android")
implementation("androidx.wear.tiles:tiles:1.1.0")
implementation("androidx.wear.tiles:tiles-material:1.1.0")

implementation("androidx.wear.watchface:watchface-complications-data-source-ktx:1.1.1")

Expand Down
Expand Up @@ -2,11 +2,15 @@ package io.homeassistant.companion.android.onboarding.integration

import android.content.Context
import android.util.Log
import androidx.wear.tiles.TileService
import dagger.hilt.android.qualifiers.ActivityContext
import io.homeassistant.companion.android.BuildConfig
import io.homeassistant.companion.android.common.data.integration.DeviceRegistration
import io.homeassistant.companion.android.common.data.servers.ServerManager
import io.homeassistant.companion.android.onboarding.getMessagingToken
import io.homeassistant.companion.android.tiles.ConversationTile
import io.homeassistant.companion.android.tiles.ShortcutsTile
import io.homeassistant.companion.android.tiles.TemplateTile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
Expand Down Expand Up @@ -47,10 +51,22 @@ class MobileAppIntegrationPresenterImpl @Inject constructor(
view.showError()
return@launch
}
updateTiles()
view.deviceRegistered()
}
}

private fun updateTiles() = mainScope.launch {
try {
val updater = TileService.getUpdater(view as Context)
updater.requestUpdate(ConversationTile::class.java)
updater.requestUpdate(ShortcutsTile::class.java)
updater.requestUpdate(TemplateTile::class.java)
} catch (e: Exception) {
Log.w(TAG, "Unable to request tiles update")
}
}

override fun onFinish() {
mainScope.cancel()
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ package io.homeassistant.companion.android.phone
import android.annotation.SuppressLint
import android.content.Intent
import android.util.Log
import androidx.wear.tiles.TileService
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.google.android.gms.wearable.DataClient
Expand Down Expand Up @@ -31,6 +32,9 @@ import io.homeassistant.companion.android.database.wear.replaceAll
import io.homeassistant.companion.android.home.HomeActivity
import io.homeassistant.companion.android.home.HomePresenterImpl
import io.homeassistant.companion.android.onboarding.getMessagingToken
import io.homeassistant.companion.android.tiles.ConversationTile
import io.homeassistant.companion.android.tiles.ShortcutsTile
import io.homeassistant.companion.android.tiles.TemplateTile
import io.homeassistant.companion.android.util.UrlUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -150,6 +154,7 @@ class PhoneSettingsListener : WearableListenerService(), DataClient.OnDataChange
)
)
serverManager.convertTemporaryServer(serverId)
updateTiles()

val intent = HomeActivity.newInstance(applicationContext)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
Expand Down Expand Up @@ -184,4 +189,15 @@ class PhoneSettingsListener : WearableListenerService(), DataClient.OnDataChange
wearPrefsRepository.setTemplateTileContent(content)
wearPrefsRepository.setTemplateTileRefreshInterval(interval)
}

private fun updateTiles() = mainScope.launch {
try {
val updater = TileService.getUpdater(applicationContext)
updater.requestUpdate(ConversationTile::class.java)
updater.requestUpdate(ShortcutsTile::class.java)
updater.requestUpdate(TemplateTile::class.java)
} catch (e: Exception) {
Log.w(TAG, "Unable to request tiles update")
}
}
}
Expand Up @@ -16,33 +16,41 @@ import androidx.wear.tiles.ResourceBuilders.Resources
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.google.common.util.concurrent.ListenableFuture
import dagger.hilt.android.AndroidEntryPoint
import io.homeassistant.companion.android.common.R
import io.homeassistant.companion.android.common.data.servers.ServerManager
import io.homeassistant.companion.android.conversation.ConversationActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.guava.future
import javax.inject.Inject
import io.homeassistant.companion.android.common.R as commonR

@AndroidEntryPoint
class ConversationTile : TileService() {
private val serviceJob = Job()
private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)

@Inject
lateinit var serverManager: ServerManager

override fun onTileRequest(requestParams: TileRequest): ListenableFuture<Tile> =
serviceScope.future {
Tile.Builder()
.setResourcesVersion("1")
.setTimeline(
Timeline.Builder().addTimelineEntry(
TimelineEntry.Builder().setLayout(
LayoutElementBuilders.Layout.Builder().setRoot(
boxLayout()
).build()
).build()
).build()
if (serverManager.isRegistered()) {
Timeline.fromLayoutElement(boxLayout())
} else {
loggedOutTimeline(
this@ConversationTile,
requestParams,
commonR.string.assist,
commonR.string.assist_log_in
)
}
).build()
}

Expand Down
@@ -0,0 +1,76 @@
package io.homeassistant.companion.android.tiles

import android.content.Context
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.wear.tiles.ActionBuilders
import androidx.wear.tiles.ColorBuilders.argb
import androidx.wear.tiles.ModifiersBuilders
import androidx.wear.tiles.RequestBuilders
import androidx.wear.tiles.TimelineBuilders.Timeline
import androidx.wear.tiles.material.ChipColors
import androidx.wear.tiles.material.Colors
import androidx.wear.tiles.material.CompactChip
import androidx.wear.tiles.material.Text
import androidx.wear.tiles.material.Typography
import androidx.wear.tiles.material.layouts.PrimaryLayout
import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.splash.SplashActivity
import io.homeassistant.companion.android.common.R as commonR

/**
* A [Timeline] with a single entry, asking the user to log in to the app to start using the tile
* with a button to open the app. The tile is using the 'Dialog' style.
*/
fun loggedOutTimeline(
context: Context,
requestParams: RequestBuilders.TileRequest,
@StringRes title: Int,
@StringRes text: Int
): Timeline {
val theme = Colors(
ContextCompat.getColor(context, R.color.colorPrimary), // Primary
ContextCompat.getColor(context, R.color.colorOnPrimary), // On primary
ContextCompat.getColor(context, R.color.colorOverlay), // Surface
ContextCompat.getColor(context, android.R.color.white) // On surface
)
val chipColors = ChipColors.primaryChipColors(theme)
val chipAction = ModifiersBuilders.Clickable.Builder()
.setId("login")
.setOnClick(
ActionBuilders.LaunchAction.Builder()
.setAndroidActivity(
ActionBuilders.AndroidActivity.Builder()
.setClassName(SplashActivity::class.java.name)
.setPackageName(context.packageName)
.build()
).build()
).build()
return Timeline.fromLayoutElement(
PrimaryLayout.Builder(requestParams.deviceParameters!!)
.setPrimaryLabelTextContent(
Text.Builder(context, context.getString(title))
.setTypography(Typography.TYPOGRAPHY_CAPTION1)
.setColor(argb(theme.primary))
.build()
)
.setContent(
Text.Builder(context, context.getString(text))
.setTypography(Typography.TYPOGRAPHY_BODY1)
.setMaxLines(10)
.setColor(argb(theme.onSurface))
.build()
)
.setPrimaryChipContent(
CompactChip.Builder(
context,
context.getString(commonR.string.login),
chipAction,
requestParams.deviceParameters!!
)
.setChipColors(chipColors)
.build()
)
.build()
)
}
Expand Up @@ -13,7 +13,6 @@ import androidx.wear.tiles.LayoutElementBuilders
import androidx.wear.tiles.LayoutElementBuilders.Box
import androidx.wear.tiles.LayoutElementBuilders.Column
import androidx.wear.tiles.LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER
import androidx.wear.tiles.LayoutElementBuilders.Layout
import androidx.wear.tiles.LayoutElementBuilders.LayoutElement
import androidx.wear.tiles.LayoutElementBuilders.Row
import androidx.wear.tiles.LayoutElementBuilders.Spacer
Expand All @@ -25,7 +24,6 @@ import androidx.wear.tiles.ResourceBuilders.Resources
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.google.common.util.concurrent.ListenableFuture
import com.mikepenz.iconics.IconicsColor
import com.mikepenz.iconics.IconicsDrawable
Expand All @@ -36,6 +34,7 @@ import com.mikepenz.iconics.utils.sizeDp
import dagger.hilt.android.AndroidEntryPoint
import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.common.data.prefs.WearPrefsRepository
import io.homeassistant.companion.android.common.data.servers.ServerManager
import io.homeassistant.companion.android.data.SimplifiedEntity
import io.homeassistant.companion.android.util.getIcon
import kotlinx.coroutines.CoroutineScope
Expand All @@ -61,6 +60,9 @@ class ShortcutsTile : TileService() {
private val serviceJob = Job()
private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)

@Inject
lateinit var serverManager: ServerManager

@Inject
lateinit var wearPrefsRepository: WearPrefsRepository

Expand All @@ -77,18 +79,20 @@ class ShortcutsTile : TileService() {
}

val entities = getEntities()
val showLabels = wearPrefsRepository.getShowShortcutText()

Tile.Builder()
.setResourcesVersion(entities.toString())
.setTimeline(
Timeline.Builder().addTimelineEntry(
TimelineEntry.Builder().setLayout(
Layout.Builder().setRoot(
layout(entities, showLabels)
).build()
).build()
).build()
if (serverManager.isRegistered()) {
timeline()
} else {
loggedOutTimeline(
this@ShortcutsTile,
requestParams,
commonR.string.shortcuts,
commonR.string.shortcuts_tile_log_in
)
}
).build()
}

Expand Down Expand Up @@ -149,6 +153,13 @@ class ShortcutsTile : TileService() {
return wearPrefsRepository.getTileShortcuts().map { SimplifiedEntity(it) }
}

private suspend fun timeline(): Timeline {
val entities = getEntities()
val showLabels = wearPrefsRepository.getShowShortcutText()

return Timeline.fromLayoutElement(layout(entities, showLabels))
}

fun layout(entities: List<SimplifiedEntity>, showLabels: Boolean): LayoutElement = Column.Builder().apply {
if (entities.isEmpty()) {
addContent(
Expand Down

0 comments on commit cc20ffe

Please sign in to comment.