From 12600ac9178292574231b76f6bf8bfb477e37f94 Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Wed, 27 Oct 2021 14:58:20 -0700
Subject: [PATCH 01/11] Convert wear home activity to compose

---
 wear/build.gradle.kts                         |  16 +-
 .../companion/android/home/HomeActivity.kt    | 201 ++++++++++++++----
 .../companion/android/home/HomePresenter.kt   |   5 +-
 .../android/home/HomePresenterImpl.kt         |  39 ++--
 .../companion/android/home/HomeView.kt        |   3 -
 wear/src/main/res/values/strings.xml          |   2 +
 6 files changed, 202 insertions(+), 64 deletions(-)

diff --git a/wear/build.gradle.kts b/wear/build.gradle.kts
index e205c7a2dac..f17e190cc1b 100644
--- a/wear/build.gradle.kts
+++ b/wear/build.gradle.kts
@@ -10,7 +10,7 @@ android {
 
     defaultConfig {
         applicationId = "io.homeassistant.companion.android"
-        minSdk = 23
+        minSdk = 25
         targetSdk = 30
 
         versionName = System.getenv("VERSION") ?: "LOCAL"
@@ -26,6 +26,11 @@ android {
 
     buildFeatures {
         viewBinding = true
+        compose = true
+    }
+
+    composeOptions {
+        kotlinCompilerExtensionVersion = "1.0.4"
     }
 
     compileOptions {
@@ -74,7 +79,7 @@ play {
 dependencies {
     implementation(project(":common"))
 
-    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2")
 
     implementation("com.google.android.material:material:1.4.0")
 
@@ -89,4 +94,11 @@ dependencies {
     implementation("com.mikepenz:iconics-core:5.3.2")
     implementation("androidx.appcompat:appcompat:1.3.1")
     implementation("com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar")
+    implementation("com.mikepenz:iconics-compose:5.3.2")
+
+    implementation("androidx.activity:activity-compose:1.3.1")
+    implementation("androidx.compose.compiler:compiler:1.0.4")
+    implementation("androidx.compose.foundation:foundation:1.0.4")
+    implementation("androidx.wear.compose:compose-foundation:1.0.0-alpha08")
+    implementation("androidx.wear.compose:compose-material:1.0.0-alpha08")
 }
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 9f6bfe4b8b2..2ab39a1cdf1 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -3,9 +3,33 @@ package io.homeassistant.companion.android.home
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.wear.widget.WearableRecyclerView
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.wear.compose.material.Button
+import androidx.wear.compose.material.ButtonDefaults
+import androidx.wear.compose.material.Chip
+import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.ScalingLazyColumn
+import androidx.wear.compose.material.ScalingLazyListState
+import androidx.wear.compose.material.Text
+import com.mikepenz.iconics.IconicsDrawable
+import com.mikepenz.iconics.compose.Image
+import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
 import io.homeassistant.companion.android.DaggerPresenterComponent
 import io.homeassistant.companion.android.PresenterModule
 import io.homeassistant.companion.android.R
@@ -13,15 +37,14 @@ import io.homeassistant.companion.android.common.dagger.GraphComponentAccessor
 import io.homeassistant.companion.android.common.data.integration.Entity
 import io.homeassistant.companion.android.onboarding.OnboardingActivity
 import io.homeassistant.companion.android.onboarding.integration.MobileAppIntegrationActivity
+import kotlinx.coroutines.runBlocking
 import javax.inject.Inject
 
-class HomeActivity : AppCompatActivity(), HomeView {
+class HomeActivity : ComponentActivity(), HomeView {
 
     @Inject
     lateinit var presenter: HomePresenter
 
-    private lateinit var adapter: HomeListAdapter
-
     companion object {
         private const val TAG = "HomeActivity"
 
@@ -33,8 +56,6 @@ class HomeActivity : AppCompatActivity(), HomeView {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
-        setContentView(R.layout.activity_home)
-
         DaggerPresenterComponent
             .builder()
             .appComponent((application as GraphComponentAccessor).appComponent)
@@ -42,16 +63,11 @@ class HomeActivity : AppCompatActivity(), HomeView {
             .build()
             .inject(this)
 
-        adapter = HomeListAdapter()
-        adapter.onSceneClicked = { entity -> presenter.onEntityClicked(entity) }
-        adapter.onButtonClicked = { id -> presenter.onButtonClicked(id) }
-
-        findViewById<WearableRecyclerView>(R.id.home_list)?.apply {
-            layoutManager = LinearLayoutManager(this@HomeActivity)
-            adapter = this@HomeActivity.adapter
+        if (presenter.onViewReady()) {
+            setContent {
+                LoadHomePage()
+            }
         }
-
-        presenter.onViewReady()
     }
 
     override fun onDestroy() {
@@ -59,27 +75,6 @@ class HomeActivity : AppCompatActivity(), HomeView {
         super.onDestroy()
     }
 
-    override fun showHomeList(scenes: List<Entity<Any>>, scripts: List<Entity<Any>>, lights: List<Entity<Any>>, covers: List<Entity<Any>>) {
-        adapter.scenes.clear()
-        adapter.scripts.clear()
-        adapter.lights.clear()
-        adapter.covers.clear()
-
-        if (scenes.isNotEmpty())
-            adapter.scenes.addAll(scenes)
-
-        if (scripts.isNotEmpty())
-            adapter.scripts.addAll(scripts)
-
-        if (lights.isNotEmpty())
-            adapter.lights.addAll(lights)
-
-        if (covers.isNotEmpty())
-            adapter.covers.addAll(covers)
-
-        adapter.notifyDataSetChanged()
-    }
-
     override fun displayOnBoarding() {
         val intent = OnboardingActivity.newInstance(this)
         startActivity(intent)
@@ -91,4 +86,134 @@ class HomeActivity : AppCompatActivity(), HomeView {
         startActivity(intent)
         finish()
     }
+
+    @Composable
+    private fun LoadHomePage() {
+
+        val entities = runBlocking {
+            presenter.getEntities()
+        }
+
+        val scenes = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "scene" }
+        val scripts = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "script" }
+        val lights = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "light" }
+        val inputBooleans = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "input_boolean" }
+        val switches = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "switch" }
+
+        ScalingLazyColumn(
+            modifier = Modifier
+                .fillMaxSize(),
+            contentPadding = PaddingValues(
+                top = 10.dp,
+                start = 10.dp,
+                end = 10.dp,
+                bottom = 40.dp
+            ),
+            horizontalAlignment = Alignment.CenterHorizontally,
+            state = ScalingLazyListState()
+        ) {
+            if (inputBooleans.isNotEmpty()) {
+                items(inputBooleans.size) { index ->
+                    if (index == 0)
+                        SetTitle(R.string.input_booleans)
+                    SetEntityUI(inputBooleans[index], index)
+                }
+            }
+            if (lights.isNotEmpty()) {
+                items(lights.size) { index ->
+                    if (index == 0)
+                        SetTitle(R.string.lights)
+                    SetEntityUI(lights[index], index)
+                }
+            }
+            if (scenes.isNotEmpty()) {
+                items(scenes.size) { index ->
+                    if (index == 0)
+                        SetTitle(R.string.scenes)
+
+                    SetEntityUI(scenes[index], index)
+                }
+            }
+            if (scripts.isNotEmpty()) {
+                items(scripts.size) { index ->
+                    if (index == 0)
+                        SetTitle(R.string.scripts)
+                    SetEntityUI(scripts[index], index)
+                }
+            }
+            if (switches.isNotEmpty()) {
+                items(switches.size) { index ->
+                    if (index == 0)
+                        SetTitle(R.string.switches)
+                    SetEntityUI(switches[index], index)
+                }
+            }
+
+            items(1) {
+                Column {
+                    SetTitle(R.string.other)
+                    Button(
+                        modifier = Modifier
+                            .width(140.dp),
+                        onClick = { presenter.onLogoutClicked() },
+                        colors = ButtonDefaults.primaryButtonColors(backgroundColor = Color.Red)
+                    ) {
+                        Row {
+                            Image(asset = CommunityMaterial.Icon.cmd_exit_run)
+                            SetTitle(R.string.logout)
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Composable
+    private fun SetEntityUI(entity: Entity<Any>, index: Int) {
+        val attributes = entity.attributes as Map<String, String>
+        val iconBitmap =
+            if (attributes["icon"]?.startsWith("mdi") == true) {
+                val icon = attributes["icon"]!!.split(":")[1]
+                IconicsDrawable(baseContext, "cmd-$icon").icon
+            } else {
+                when (entity.entityId.split(".")[0]) {
+                    "input_boolean", "switch" -> CommunityMaterial.Icon2.cmd_light_switch
+                    "light" -> CommunityMaterial.Icon2.cmd_lightbulb
+                    "script" -> CommunityMaterial.Icon3.cmd_script_text_outline
+                    "scene" -> CommunityMaterial.Icon3.cmd_palette_outline
+                    else -> CommunityMaterial.Icon.cmd_cellphone
+                }
+            }
+
+        Chip(
+            modifier = Modifier
+                .width(140.dp)
+                .padding(top = if (index == 0) 30.dp else 10.dp),
+            icon = {
+                if (iconBitmap != null) {
+                    Image(asset = iconBitmap)
+                } else
+                    Image(asset = CommunityMaterial.Icon.cmd_cellphone)
+            },
+            label = {
+                Text(
+                    text = attributes["friendly_name"].toString()
+                )
+            },
+            onClick = { presenter.onEntityClicked(entity) },
+            colors = ChipDefaults.primaryChipColors(backgroundColor = Color.Blue, iconTintColor = Color.White)
+        )
+    }
+
+    @Composable
+    private fun SetTitle(id: Int) {
+        Text(
+            text = stringResource(id = id),
+            textAlign = TextAlign.Center,
+            fontSize = 15.sp,
+            fontWeight = FontWeight.Bold,
+            modifier = Modifier
+                .padding(start = 15.dp)
+        )
+    }
 }
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
index bc68056f4e8..25d748f45b4 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
@@ -4,9 +4,10 @@ import io.homeassistant.companion.android.common.data.integration.Entity
 
 interface HomePresenter {
 
-    fun onViewReady()
+    fun onViewReady(): Boolean
     fun onEntityClicked(entity: Entity<Any>)
-    fun onButtonClicked(id: String)
     fun onLogoutClicked()
     fun onFinish()
+
+    suspend fun getEntities(): Array<Entity<Any>>
 }
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
index 7cbbc9ef804..87cdc3fcf9f 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
@@ -12,6 +12,7 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
 import javax.inject.Inject
 
 class HomePresenterImpl @Inject constructor(
@@ -21,29 +22,43 @@ class HomePresenterImpl @Inject constructor(
 ) : HomePresenter {
 
     companion object {
+        private val toggleDomains = listOf(
+            "cover", "fan", "humidifier", "input_boolean", "light",
+            "media_player", "remote", "siren", "switch"
+        )
         const val TAG = "HomePresenter"
     }
 
     private val mainScope: CoroutineScope = CoroutineScope(Dispatchers.Main + Job())
 
-    override fun onViewReady() {
-        mainScope.launch {
+    override fun onViewReady(): Boolean {
+        var isRegistered = false
+        runBlocking {
             val sessionValid = authenticationUseCase.getSessionState() == SessionState.CONNECTED
             if (sessionValid && integrationUseCase.isRegistered()) {
                 resyncRegistration()
-                // We'll stay on HomeActivity, so start loading entities
-                processEntities(integrationUseCase.getEntities())
+                isRegistered = true
             } else if (sessionValid) {
                 view.displayMobileAppIntegration()
             } else {
                 view.displayOnBoarding()
             }
         }
+        return isRegistered
+    }
+
+    override suspend fun getEntities(): Array<Entity<Any>> {
+        return try {
+            integrationUseCase.getEntities()
+        } catch (e: Exception) {
+            Log.e(TAG, "Unable to get entities", e)
+            emptyArray()
+        }
     }
 
     override fun onEntityClicked(entity: Entity<Any>) {
 
-        if (entity.entityId.split(".")[0] == "light") {
+        if (entity.entityId.split(".")[0] in toggleDomains) {
             mainScope.launch {
                 integrationUseCase.callService(
                     entity.entityId.split(".")[0],
@@ -62,12 +77,6 @@ class HomePresenterImpl @Inject constructor(
         }
     }
 
-    override fun onButtonClicked(id: String) {
-        if (id == HomeListAdapter.BUTTON_ID_LOGOUT) {
-            onLogoutClicked()
-        }
-    }
-
     override fun onLogoutClicked() {
         mainScope.launch {
             authenticationUseCase.revokeSession()
@@ -79,14 +88,6 @@ class HomePresenterImpl @Inject constructor(
         mainScope.cancel()
     }
 
-    private fun processEntities(entities: Array<Entity<Any>>) {
-        val scenes = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "scene" }
-        val scripts = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "script" }
-        val lights = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "light" }
-        val covers = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "cover" }
-        view.showHomeList(scenes, scripts, lights, covers)
-    }
-
     private fun resyncRegistration() {
         mainScope.launch {
             try {
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeView.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeView.kt
index 9f2d4d67afe..423c5c0ffbb 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeView.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeView.kt
@@ -1,9 +1,6 @@
 package io.homeassistant.companion.android.home
 
-import io.homeassistant.companion.android.common.data.integration.Entity
-
 interface HomeView {
-    fun showHomeList(scenes: List<Entity<Any>>, scripts: List<Entity<Any>>, lights: List<Entity<Any>>, covers: List<Entity<Any>>)
 
     fun displayOnBoarding()
     fun displayMobileAppIntegration()
diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml
index 8e4a2837bdf..57bad2b4db1 100644
--- a/wear/src/main/res/values/strings.xml
+++ b/wear/src/main/res/values/strings.xml
@@ -31,4 +31,6 @@
     <string name="username">Username</string>
     <string name="version">Version: %s</string>
     <string name="lights">Lights</string>
+    <string name="input_booleans">Input Booleans</string>
+    <string name="switches">Switches</string>
 </resources>
\ No newline at end of file

From a7286a07297c01fe8941f8a877c783d814543659 Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Wed, 27 Oct 2021 15:36:55 -0700
Subject: [PATCH 02/11] Bump compose libraries and make UI consistent

---
 wear/build.gradle.kts                                         | 4 ++--
 .../io/homeassistant/companion/android/home/HomeActivity.kt   | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/wear/build.gradle.kts b/wear/build.gradle.kts
index f17e190cc1b..f9f6e63195d 100644
--- a/wear/build.gradle.kts
+++ b/wear/build.gradle.kts
@@ -99,6 +99,6 @@ dependencies {
     implementation("androidx.activity:activity-compose:1.3.1")
     implementation("androidx.compose.compiler:compiler:1.0.4")
     implementation("androidx.compose.foundation:foundation:1.0.4")
-    implementation("androidx.wear.compose:compose-foundation:1.0.0-alpha08")
-    implementation("androidx.wear.compose:compose-material:1.0.0-alpha08")
+    implementation("androidx.wear.compose:compose-foundation:1.0.0-alpha09")
+    implementation("androidx.wear.compose:compose-material:1.0.0-alpha09")
 }
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 2ab39a1cdf1..79a3649ef97 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -15,6 +15,7 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.style.TextAlign
@@ -201,7 +202,7 @@ class HomeActivity : ComponentActivity(), HomeView {
                 )
             },
             onClick = { presenter.onEntityClicked(entity) },
-            colors = ChipDefaults.primaryChipColors(backgroundColor = Color.Blue, iconTintColor = Color.White)
+            colors = ChipDefaults.primaryChipColors(backgroundColor = colorResource(id = R.color.colorAccent), contentColor = Color.Black)
         )
     }
 

From 255c6181b9fe448db3e2bfed9171faafdbbcf17f Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Thu, 28 Oct 2021 10:14:06 -0700
Subject: [PATCH 03/11] UI fixes based on review comments

---
 .../companion/android/home/HomeActivity.kt    | 166 ++++++++++--------
 1 file changed, 95 insertions(+), 71 deletions(-)

diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 79a3649ef97..6691ad1aac6 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -7,10 +7,9 @@ import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -21,13 +20,15 @@ import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
-import androidx.wear.compose.material.Button
-import androidx.wear.compose.material.ButtonDefaults
 import androidx.wear.compose.material.Chip
 import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.PositionIndicator
+import androidx.wear.compose.material.Scaffold
 import androidx.wear.compose.material.ScalingLazyColumn
 import androidx.wear.compose.material.ScalingLazyListState
 import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.rememberScalingLazyListState
 import com.mikepenz.iconics.IconicsDrawable
 import com.mikepenz.iconics.compose.Image
 import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
@@ -95,73 +96,96 @@ class HomeActivity : ComponentActivity(), HomeView {
             presenter.getEntities()
         }
 
-        val scenes = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "scene" }
-        val scripts = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "script" }
-        val lights = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "light" }
-        val inputBooleans = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "input_boolean" }
-        val switches = entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "switch" }
-
-        ScalingLazyColumn(
-            modifier = Modifier
-                .fillMaxSize(),
-            contentPadding = PaddingValues(
-                top = 10.dp,
-                start = 10.dp,
-                end = 10.dp,
-                bottom = 40.dp
-            ),
-            horizontalAlignment = Alignment.CenterHorizontally,
-            state = ScalingLazyListState()
-        ) {
-            if (inputBooleans.isNotEmpty()) {
-                items(inputBooleans.size) { index ->
-                    if (index == 0)
-                        SetTitle(R.string.input_booleans)
-                    SetEntityUI(inputBooleans[index], index)
-                }
-            }
-            if (lights.isNotEmpty()) {
-                items(lights.size) { index ->
-                    if (index == 0)
-                        SetTitle(R.string.lights)
-                    SetEntityUI(lights[index], index)
+        val scenes =
+            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "scene" }
+        val scripts =
+            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "script" }
+        val lights =
+            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "light" }
+        val inputBooleans = entities.sortedBy { it.entityId }
+            .filter { it.entityId.split(".")[0] == "input_boolean" }
+        val switches =
+            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "switch" }
+
+        val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState()
+
+        MaterialTheme {
+            Scaffold(
+                positionIndicator = {
+                    if (scalingLazyListState.isScrollInProgress)
+                        PositionIndicator(scalingLazyListState = scalingLazyListState)
                 }
-            }
-            if (scenes.isNotEmpty()) {
-                items(scenes.size) { index ->
-                    if (index == 0)
-                        SetTitle(R.string.scenes)
+            ) {
+                ScalingLazyColumn(
+                    modifier = Modifier
+                        .fillMaxSize(),
+                    contentPadding = PaddingValues(
+                        top = 10.dp,
+                        start = 10.dp,
+                        end = 10.dp,
+                        bottom = 40.dp
+                    ),
+                    horizontalAlignment = Alignment.CenterHorizontally,
+                    state = scalingLazyListState
+                ) {
+                    if (inputBooleans.isNotEmpty()) {
+                        items(inputBooleans.size) { index ->
+                            if (index == 0)
+                                SetTitle(R.string.input_booleans)
+                            SetEntityUI(inputBooleans[index], index)
+                        }
+                    }
+                    if (lights.isNotEmpty()) {
+                        items(lights.size) { index ->
+                            if (index == 0)
+                                SetTitle(R.string.lights)
+                            SetEntityUI(lights[index], index)
+                        }
+                    }
+                    if (scenes.isNotEmpty()) {
+                        items(scenes.size) { index ->
+                            if (index == 0)
+                                SetTitle(R.string.scenes)
 
-                    SetEntityUI(scenes[index], index)
-                }
-            }
-            if (scripts.isNotEmpty()) {
-                items(scripts.size) { index ->
-                    if (index == 0)
-                        SetTitle(R.string.scripts)
-                    SetEntityUI(scripts[index], index)
-                }
-            }
-            if (switches.isNotEmpty()) {
-                items(switches.size) { index ->
-                    if (index == 0)
-                        SetTitle(R.string.switches)
-                    SetEntityUI(switches[index], index)
-                }
-            }
+                            SetEntityUI(scenes[index], index)
+                        }
+                    }
+                    if (scripts.isNotEmpty()) {
+                        items(scripts.size) { index ->
+                            if (index == 0)
+                                SetTitle(R.string.scripts)
+                            SetEntityUI(scripts[index], index)
+                        }
+                    }
+                    if (switches.isNotEmpty()) {
+                        items(switches.size) { index ->
+                            if (index == 0)
+                                SetTitle(R.string.switches)
+                            SetEntityUI(switches[index], index)
+                        }
+                    }
 
-            items(1) {
-                Column {
-                    SetTitle(R.string.other)
-                    Button(
-                        modifier = Modifier
-                            .width(140.dp),
-                        onClick = { presenter.onLogoutClicked() },
-                        colors = ButtonDefaults.primaryButtonColors(backgroundColor = Color.Red)
-                    ) {
-                        Row {
-                            Image(asset = CommunityMaterial.Icon.cmd_exit_run)
-                            SetTitle(R.string.logout)
+                    item {
+                        Column {
+                            SetTitle(R.string.other)
+                            Chip(
+                                modifier = Modifier
+                                    .fillMaxWidth()
+                                    .padding(top = 10.dp),
+                                icon = {
+                                    Image(asset = CommunityMaterial.Icon.cmd_exit_run)
+                                },
+                                label = {
+                                    Text(
+                                        text = stringResource(id = R.string.logout)
+                                    )
+                                },
+                                onClick = { presenter.onLogoutClicked() },
+                                colors = ChipDefaults.primaryChipColors(
+                                    backgroundColor = Color.Red,
+                                    contentColor = Color.Black
+                                )
+                            )
                         }
                     }
                 }
@@ -188,7 +212,7 @@ class HomeActivity : ComponentActivity(), HomeView {
 
         Chip(
             modifier = Modifier
-                .width(140.dp)
+                .fillMaxWidth()
                 .padding(top = if (index == 0) 30.dp else 10.dp),
             icon = {
                 if (iconBitmap != null) {
@@ -198,7 +222,7 @@ class HomeActivity : ComponentActivity(), HomeView {
             },
             label = {
                 Text(
-                    text = attributes["friendly_name"].toString()
+                    text = attributes["friendly_name"].toString().take(30)
                 )
             },
             onClick = { presenter.onEntityClicked(entity) },
@@ -214,7 +238,7 @@ class HomeActivity : ComponentActivity(), HomeView {
             fontSize = 15.sp,
             fontWeight = FontWeight.Bold,
             modifier = Modifier
-                .padding(start = 15.dp)
+                .fillMaxWidth()
         )
     }
 }

From c6f6c15c44e7cd48aeaaf9f72ceb537ec1964587 Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Thu, 28 Oct 2021 10:36:15 -0700
Subject: [PATCH 04/11] Use chip overflow and max lines instead of take

---
 .../io/homeassistant/companion/android/home/HomeActivity.kt  | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 6691ad1aac6..78ca06687de 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -18,6 +18,7 @@ import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.wear.compose.material.Chip
@@ -222,7 +223,9 @@ class HomeActivity : ComponentActivity(), HomeView {
             },
             label = {
                 Text(
-                    text = attributes["friendly_name"].toString().take(30)
+                    text = attributes["friendly_name"].toString(),
+                    maxLines = 2,
+                    overflow = TextOverflow.Ellipsis
                 )
             },
             onClick = { presenter.onEntityClicked(entity) },

From f29995873fb926ae9f0700a65a29917c65821f71 Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Thu, 28 Oct 2021 10:51:16 -0700
Subject: [PATCH 05/11] Bump activity compose dependency in wear

---
 wear/build.gradle.kts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wear/build.gradle.kts b/wear/build.gradle.kts
index f9f6e63195d..e040bc679c2 100644
--- a/wear/build.gradle.kts
+++ b/wear/build.gradle.kts
@@ -96,7 +96,7 @@ dependencies {
     implementation("com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar")
     implementation("com.mikepenz:iconics-compose:5.3.2")
 
-    implementation("androidx.activity:activity-compose:1.3.1")
+    implementation("androidx.activity:activity-compose:1.4.0")
     implementation("androidx.compose.compiler:compiler:1.0.4")
     implementation("androidx.compose.foundation:foundation:1.0.4")
     implementation("androidx.wear.compose:compose-foundation:1.0.0-alpha09")

From e804e2301c035c4976accd8a438f27db172a752e Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Thu, 28 Oct 2021 13:17:11 -0700
Subject: [PATCH 06/11] Clean up old files

---
 .../companion/android/home/HomeListAdapter.kt | 130 ------------------
 .../android/viewHolders/ButtonViewHolder.kt   |  27 ----
 .../viewHolders/EntityButtonViewHolder.kt     |  58 --------
 wear/src/main/res/layout/activity_home.xml    |  12 --
 4 files changed, 227 deletions(-)
 delete mode 100644 wear/src/main/java/io/homeassistant/companion/android/home/HomeListAdapter.kt
 delete mode 100644 wear/src/main/java/io/homeassistant/companion/android/viewHolders/ButtonViewHolder.kt
 delete mode 100644 wear/src/main/java/io/homeassistant/companion/android/viewHolders/EntityButtonViewHolder.kt
 delete mode 100644 wear/src/main/res/layout/activity_home.xml

diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeListAdapter.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeListAdapter.kt
deleted file mode 100644
index 68e24e40efa..00000000000
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeListAdapter.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-package io.homeassistant.companion.android.home
-
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import io.homeassistant.companion.android.R
-import io.homeassistant.companion.android.common.data.integration.Entity
-import io.homeassistant.companion.android.viewHolders.ButtonViewHolder
-import io.homeassistant.companion.android.viewHolders.EntityButtonViewHolder
-import io.homeassistant.companion.android.viewHolders.HeaderViewHolder
-import io.homeassistant.companion.android.viewHolders.LoadingViewHolder
-import kotlin.math.max
-
-class HomeListAdapter() : RecyclerView.Adapter<ViewHolder>() {
-
-    lateinit var onSceneClicked: (Entity<Any>) -> Unit
-    lateinit var onButtonClicked: (String) -> Unit
-
-    val scenes = arrayListOf<Entity<Any>>()
-    val scripts = arrayListOf<Entity<Any>>()
-    val lights = arrayListOf<Entity<Any>>()
-    val covers = arrayListOf<Entity<Any>>()
-    val dataList = mutableListOf<Entity<Any>>()
-
-    companion object {
-        private const val TYPE_SCENE = 1 // Used for scenes and scripts
-        private const val TYPE_HEADER = 2
-        private const val TYPE_LOADING = 3
-        private const val TYPE_BUTTON = 4
-
-        const val BUTTON_ID_LOGOUT: String = "logout"
-
-        private const val TAG = "HomeListAdapter"
-    }
-
-    override fun onCreateViewHolder(
-        parent: ViewGroup,
-        viewType: Int
-    ): ViewHolder {
-        return when (viewType) {
-            TYPE_SCENE -> {
-                val view = LayoutInflater.from(parent.context)
-                    .inflate(R.layout.listitem_entity_button, parent, false)
-                EntityButtonViewHolder(view, onSceneClicked)
-            }
-            TYPE_HEADER -> {
-                val view = LayoutInflater.from(parent.context)
-                    .inflate(R.layout.listitem_header, parent, false)
-                HeaderViewHolder(view)
-            }
-            TYPE_BUTTON -> {
-                val view = LayoutInflater.from(parent.context)
-                    .inflate(R.layout.listitem_button, parent, false)
-                ButtonViewHolder(view, onButtonClicked)
-            }
-            else -> {
-                val view = LayoutInflater.from(parent.context)
-                    .inflate(R.layout.listitem_loading, parent, false)
-                LoadingViewHolder(view)
-            }
-        }
-    }
-
-    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
-        try {
-            if (holder is EntityButtonViewHolder) {
-                if (position < scenes.size + 1) {
-                    holder.entity = scenes[position - 1]
-                } else if (position > scenes.size + 1 + scripts.size + 1) {
-                    holder.entity = lights[position - 3 - scenes.size - scripts.size]
-                } else
-                    holder.entity = scripts[position - 2 - scenes.size]
-            } else if (holder is HeaderViewHolder) {
-                when (position) {
-                    0 -> holder.headerTextView.setText(R.string.scenes)
-                    scenes.size + 1 -> holder.headerTextView.setText(R.string.scripts)
-                    scenes.size + scripts.size + 2 -> holder.headerTextView.setText(R.string.lights)
-                    else -> holder.headerTextView.setText(R.string.other)
-                }
-            } else if (holder is ButtonViewHolder) {
-                holder.txtName.setText(R.string.logout)
-                holder.id = BUTTON_ID_LOGOUT
-                holder.color = R.color.colorWarning
-            }
-        } catch (e: Exception) {
-            Log.e(TAG, "Unable to add entities to list", e)
-        }
-    }
-
-    override fun getItemCount() = max(scenes.size + scripts.size + lights.size + 5, 7)
-
-    override fun getItemViewType(position: Int): Int {
-        /*
-        Current layout contains of three sections:
-        # Scenes
-        - scene 1
-        - scene 2
-        - etc
-        # Scripts
-        - script 1
-        - script 2
-        - etc
-        # Other
-        - Logout
-
-        Envisioned final layout:
-        # Scenes
-        - 3 favorite scenes
-        - More scenes button
-        # Devices
-        - 3 favorite devices
-        - More devices button
-        # Scripts
-        - 3 favorite scripts
-        - More scripts button
-        # Other
-        - Settings
-         */
-
-        return when {
-            position == 0 || position == scenes.size + 1 || position == scenes.size + scripts.size + 2 || position == itemCount - 2 -> TYPE_HEADER
-            position == itemCount - 1 -> TYPE_BUTTON
-            position < scenes.size + 1 && scenes.size > 0 -> TYPE_SCENE
-            position > scenes.size + 1 && scripts.size > 0 -> TYPE_SCENE
-            else -> TYPE_LOADING
-        }
-    }
-}
diff --git a/wear/src/main/java/io/homeassistant/companion/android/viewHolders/ButtonViewHolder.kt b/wear/src/main/java/io/homeassistant/companion/android/viewHolders/ButtonViewHolder.kt
deleted file mode 100644
index 33c58dd8a5c..00000000000
--- a/wear/src/main/java/io/homeassistant/companion/android/viewHolders/ButtonViewHolder.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.homeassistant.companion.android.viewHolders
-
-import android.view.View
-import android.widget.TextView
-import androidx.core.content.ContextCompat
-import androidx.recyclerview.widget.RecyclerView
-import io.homeassistant.companion.android.R
-
-class ButtonViewHolder(val v: View, val onClick: (String) -> Unit) :
-    RecyclerView.ViewHolder(v) {
-
-    var txtName: TextView = v.findViewById(R.id.txt_name)
-
-    var color: Int? = null
-        set(value) {
-            v.background.mutate().setTint(ContextCompat.getColor(v.context, value!!))
-            field = value
-        }
-
-    var id: String = ""
-
-    init {
-        v.setOnClickListener {
-            onClick(id)
-        }
-    }
-}
diff --git a/wear/src/main/java/io/homeassistant/companion/android/viewHolders/EntityButtonViewHolder.kt b/wear/src/main/java/io/homeassistant/companion/android/viewHolders/EntityButtonViewHolder.kt
deleted file mode 100644
index 098f60cd142..00000000000
--- a/wear/src/main/java/io/homeassistant/companion/android/viewHolders/EntityButtonViewHolder.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package io.homeassistant.companion.android.viewHolders
-
-import android.graphics.Color
-import android.view.View
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import com.mikepenz.iconics.IconicsDrawable
-import com.mikepenz.iconics.utils.colorInt
-import com.mikepenz.iconics.utils.sizeDp
-import io.homeassistant.companion.android.R
-import io.homeassistant.companion.android.common.data.integration.Entity
-
-class EntityButtonViewHolder(v: View, val onClick: (Entity<Any>) -> Unit) :
-    RecyclerView.ViewHolder(v) {
-
-    private var txtName: TextView = v.findViewById(R.id.txt_name)
-    private var imgIcon: ImageView = v.findViewById(R.id.img_icon)
-
-    var entity: Entity<Any>? = null
-        set(value) {
-            val entityAttributes = value?.attributes as Map<String, String>
-            txtName.text = entityAttributes["friendly_name"]
-
-            if (entityAttributes["icon"]?.startsWith("mdi") == true) {
-                val icon: String = entityAttributes["icon"]!!.split(":")[1]
-                val iconDrawable = IconicsDrawable(imgIcon.context, "cmd-$icon").apply {
-                    colorInt = Color.WHITE
-                    sizeDp = 24
-                }
-                imgIcon.setImageDrawable(iconDrawable)
-            } else {
-                // Set default icon
-                when {
-                    value.entityId.split(".")[0] == "script" -> {
-                        imgIcon.setImageResource(R.drawable.ic_scripts)
-                    }
-                    value.entityId.split(".")[0] == "light" -> {
-                        imgIcon.setImageResource(R.drawable.ic_light)
-                    }
-                    value.entityId.split(".")[0] == "cover" -> {
-                        imgIcon.setImageResource(R.drawable.ic_garage)
-                    }
-                    else -> {
-                        imgIcon.setImageResource(R.drawable.ic_scenes)
-                    }
-                }
-            }
-
-            field = value
-        }
-
-    init {
-        v.setOnClickListener {
-            entity?.let { onClick(it) }
-        }
-    }
-}
diff --git a/wear/src/main/res/layout/activity_home.xml b/wear/src/main/res/layout/activity_home.xml
deleted file mode 100644
index fc005e51daa..00000000000
--- a/wear/src/main/res/layout/activity_home.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.wear.widget.WearableRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/home_list"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:scrollbars="vertical"
-    android:paddingBottom="48dp"
-    android:clipToPadding="false"
-    tools:listitem="@layout/listitem_entity_button">
-    <requestFocus />
-</androidx.wear.widget.WearableRecyclerView>

From 2aff414b5cd716ff9804fd7d718f3476b92a4cf3 Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Fri, 29 Oct 2021 07:49:41 -0700
Subject: [PATCH 07/11] Remove more unused files

---
 wear/src/main/res/drawable/ic_garage.xml      |  8 ----
 wear/src/main/res/drawable/ic_light.xml       |  8 ----
 wear/src/main/res/drawable/ic_scenes.xml      | 10 -----
 wear/src/main/res/drawable/ic_scripts.xml     |  8 ----
 wear/src/main/res/layout/listitem_button.xml  | 24 ------------
 .../res/layout/listitem_entity_button.xml     | 37 -------------------
 6 files changed, 95 deletions(-)
 delete mode 100644 wear/src/main/res/drawable/ic_garage.xml
 delete mode 100644 wear/src/main/res/drawable/ic_light.xml
 delete mode 100644 wear/src/main/res/drawable/ic_scenes.xml
 delete mode 100644 wear/src/main/res/drawable/ic_scripts.xml
 delete mode 100644 wear/src/main/res/layout/listitem_button.xml
 delete mode 100644 wear/src/main/res/layout/listitem_entity_button.xml

diff --git a/wear/src/main/res/drawable/ic_garage.xml b/wear/src/main/res/drawable/ic_garage.xml
deleted file mode 100644
index 338bcdc2e2e..00000000000
--- a/wear/src/main/res/drawable/ic_garage.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<!-- drawable/garage.xml -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:width="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path android:fillColor="#000" android:pathData="M19,20H17V11H7V20H5V9L12,5L19,9V20M8,12H16V14H8V12M8,15H16V17H8V15M16,18V20H8V18H16Z" />
-</vector>
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_light.xml b/wear/src/main/res/drawable/ic_light.xml
deleted file mode 100644
index 9163645e35d..00000000000
--- a/wear/src/main/res/drawable/ic_light.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<!-- drawable/lightbulb.xml -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:width="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path android:fillColor="#000" android:pathData="M12,2A7,7 0 0,0 5,9C5,11.38 6.19,13.47 8,14.74V17A1,1 0 0,0 9,18H15A1,1 0 0,0 16,17V14.74C17.81,13.47 19,11.38 19,9A7,7 0 0,0 12,2M9,21A1,1 0 0,0 10,22H14A1,1 0 0,0 15,21V20H9V21Z" />
-</vector>
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_scenes.xml b/wear/src/main/res/drawable/ic_scenes.xml
deleted file mode 100644
index 4bf15508591..00000000000
--- a/wear/src/main/res/drawable/ic_scenes.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
-</vector>
diff --git a/wear/src/main/res/drawable/ic_scripts.xml b/wear/src/main/res/drawable/ic_scripts.xml
deleted file mode 100644
index 8e2a94bdb43..00000000000
--- a/wear/src/main/res/drawable/ic_scripts.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<!-- drawable/script_text.xml -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:width="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-    <path android:fillColor="#000" android:pathData="M17.8,20C17.4,21.2 16.3,22 15,22H5C3.3,22 2,20.7 2,19V18H5L14.2,18C14.6,19.2 15.7,20 17,20H17.8M19,2C20.7,2 22,3.3 22,5V6H20V5C20,4.4 19.6,4 19,4C18.4,4 18,4.4 18,5V18H17C16.4,18 16,17.6 16,17V16H5V5C5,3.3 6.3,2 8,2H19M8,6V8H15V6H8M8,10V12H14V10H8Z" />
-</vector>
\ No newline at end of file
diff --git a/wear/src/main/res/layout/listitem_button.xml b/wear/src/main/res/layout/listitem_button.xml
deleted file mode 100644
index 494aa9aa180..00000000000
--- a/wear/src/main/res/layout/listitem_button.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="48dp"
-    android:layout_marginStart="8dp"
-    android:layout_marginTop="2dp"
-    android:layout_marginEnd="8dp"
-    android:layout_marginBottom="2dp"
-    android:background="@drawable/item_background"
-    android:orientation="vertical"
-    android:padding="12dp"
-    android:backgroundTintMode="src_over">
-
-    <androidx.appcompat.widget.AppCompatTextView
-        android:id="@+id/txt_name"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
-        android:ellipsize="marquee"
-        android:maxLines="1"
-        tools:text="@string/other" />
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/wear/src/main/res/layout/listitem_entity_button.xml b/wear/src/main/res/layout/listitem_entity_button.xml
deleted file mode 100644
index c2f70fbfc75..00000000000
--- a/wear/src/main/res/layout/listitem_entity_button.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="48dp"
-    android:layout_marginStart="8dp"
-    android:layout_marginTop="2dp"
-    android:layout_marginEnd="8dp"
-    android:layout_marginBottom="2dp"
-    android:background="@drawable/item_background"
-    android:orientation="vertical"
-    android:padding="12dp">
-
-    <ImageView
-        android:id="@+id/img_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentStart="true"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentBottom="true"
-        android:layout_marginEnd="8dp"
-        app:tint="@color/white"
-        app:srcCompat="@drawable/ic_scenes" />
-
-    <androidx.appcompat.widget.AppCompatTextView
-        android:id="@+id/txt_name"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@id/img_icon"
-        android:layout_alignParentTop="true"
-        android:layout_toEndOf="@+id/img_icon"
-        android:ellipsize="marquee"
-        android:maxLines="1"
-        tools:text="@string/scene" />
-
-</RelativeLayout>
\ No newline at end of file

From 88765df033244f17ee5b8a4ceecd86802deb9f7b Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Fri, 29 Oct 2021 14:29:00 -0700
Subject: [PATCH 08/11] Pass entities into composable and use rememberSaveable
 for the lists

---
 .../companion/android/home/HomeActivity.kt    | 48 ++++++++++---------
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 78ca06687de..8e8c1886fab 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -67,8 +68,11 @@ class HomeActivity : ComponentActivity(), HomeView {
             .inject(this)
 
         if (presenter.onViewReady()) {
+            val entities = runBlocking {
+                presenter.getEntities()
+            }
             setContent {
-                LoadHomePage()
+                LoadHomePage(entities)
             }
         }
     }
@@ -91,11 +95,7 @@ class HomeActivity : ComponentActivity(), HomeView {
     }
 
     @Composable
-    private fun LoadHomePage() {
-
-        val entities = runBlocking {
-            presenter.getEntities()
-        }
+    private fun LoadHomePage(entities: Array<Entity<Any>>) {
 
         val scenes =
             entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "scene" }
@@ -109,7 +109,11 @@ class HomeActivity : ComponentActivity(), HomeView {
             entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "switch" }
 
         val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState()
-
+        val scenesRemembered = rememberSaveable { scenes }
+        val inputBooleansRemembered = rememberSaveable { inputBooleans }
+        val lightsRemembered = rememberSaveable { lights }
+        val scriptsRemembered = rememberSaveable { scripts }
+        val switchesRemembered = rememberSaveable { switches }
         MaterialTheme {
             Scaffold(
                 positionIndicator = {
@@ -129,40 +133,40 @@ class HomeActivity : ComponentActivity(), HomeView {
                     horizontalAlignment = Alignment.CenterHorizontally,
                     state = scalingLazyListState
                 ) {
-                    if (inputBooleans.isNotEmpty()) {
-                        items(inputBooleans.size) { index ->
+                    if (inputBooleansRemembered.isNotEmpty()) {
+                        items(inputBooleansRemembered.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.input_booleans)
-                            SetEntityUI(inputBooleans[index], index)
+                            SetEntityUI(inputBooleansRemembered[index], index)
                         }
                     }
-                    if (lights.isNotEmpty()) {
-                        items(lights.size) { index ->
+                    if (lightsRemembered.isNotEmpty()) {
+                        items(lightsRemembered.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.lights)
-                            SetEntityUI(lights[index], index)
+                            SetEntityUI(lightsRemembered[index], index)
                         }
                     }
-                    if (scenes.isNotEmpty()) {
-                        items(scenes.size) { index ->
+                    if (scenesRemembered.isNotEmpty()) {
+                        items(scenesRemembered.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.scenes)
 
-                            SetEntityUI(scenes[index], index)
+                            SetEntityUI(scenesRemembered[index], index)
                         }
                     }
-                    if (scripts.isNotEmpty()) {
-                        items(scripts.size) { index ->
+                    if (scriptsRemembered.isNotEmpty()) {
+                        items(scriptsRemembered.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.scripts)
-                            SetEntityUI(scripts[index], index)
+                            SetEntityUI(scriptsRemembered[index], index)
                         }
                     }
-                    if (switches.isNotEmpty()) {
-                        items(switches.size) { index ->
+                    if (switchesRemembered.isNotEmpty()) {
+                        items(switchesRemembered.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.switches)
-                            SetEntityUI(switches[index], index)
+                            SetEntityUI(switchesRemembered[index], index)
                         }
                     }
 

From a54b8e65fc094794cd3a71d35ba2aa1cf8917a1d Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Mon, 1 Nov 2021 15:41:59 -0700
Subject: [PATCH 09/11] Move getEntities to ViewModel for recomposition

---
 .../companion/android/home/HomeActivity.kt    | 48 +++++++++----------
 .../companion/android/home/HomePresenter.kt   |  2 -
 .../android/home/HomePresenterImpl.kt         |  9 ----
 .../android/viewModels/EntityViewModel.kt     | 41 ++++++++++++++++
 .../android/viewModels/ViewModuleComponent.kt | 10 ++++
 5 files changed, 73 insertions(+), 37 deletions(-)
 create mode 100755 wear/src/main/java/io/homeassistant/companion/android/viewModels/EntityViewModel.kt
 create mode 100755 wear/src/main/java/io/homeassistant/companion/android/viewModels/ViewModuleComponent.kt

diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 8e8c1886fab..58b6632ada6 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -5,13 +5,13 @@ import android.content.Intent
 import android.os.Bundle
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
+import androidx.activity.viewModels
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -41,7 +41,7 @@ import io.homeassistant.companion.android.common.dagger.GraphComponentAccessor
 import io.homeassistant.companion.android.common.data.integration.Entity
 import io.homeassistant.companion.android.onboarding.OnboardingActivity
 import io.homeassistant.companion.android.onboarding.integration.MobileAppIntegrationActivity
-import kotlinx.coroutines.runBlocking
+import io.homeassistant.companion.android.viewModels.EntityViewModel
 import javax.inject.Inject
 
 class HomeActivity : ComponentActivity(), HomeView {
@@ -49,6 +49,8 @@ class HomeActivity : ComponentActivity(), HomeView {
     @Inject
     lateinit var presenter: HomePresenter
 
+    val entityViewModel by viewModels<EntityViewModel>()
+
     companion object {
         private const val TAG = "HomeActivity"
 
@@ -68,11 +70,9 @@ class HomeActivity : ComponentActivity(), HomeView {
             .inject(this)
 
         if (presenter.onViewReady()) {
-            val entities = runBlocking {
-                presenter.getEntities()
-            }
             setContent {
-                LoadHomePage(entities)
+                LoadHomePage(entities = entityViewModel.entitiesResponse)
+                entityViewModel.getEntities(applicationContext)
             }
         }
     }
@@ -109,11 +109,7 @@ class HomeActivity : ComponentActivity(), HomeView {
             entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "switch" }
 
         val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState()
-        val scenesRemembered = rememberSaveable { scenes }
-        val inputBooleansRemembered = rememberSaveable { inputBooleans }
-        val lightsRemembered = rememberSaveable { lights }
-        val scriptsRemembered = rememberSaveable { scripts }
-        val switchesRemembered = rememberSaveable { switches }
+
         MaterialTheme {
             Scaffold(
                 positionIndicator = {
@@ -133,40 +129,40 @@ class HomeActivity : ComponentActivity(), HomeView {
                     horizontalAlignment = Alignment.CenterHorizontally,
                     state = scalingLazyListState
                 ) {
-                    if (inputBooleansRemembered.isNotEmpty()) {
-                        items(inputBooleansRemembered.size) { index ->
+                    if (inputBooleans.isNotEmpty()) {
+                        items(inputBooleans.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.input_booleans)
-                            SetEntityUI(inputBooleansRemembered[index], index)
+                            SetEntityUI(inputBooleans[index], index)
                         }
                     }
-                    if (lightsRemembered.isNotEmpty()) {
-                        items(lightsRemembered.size) { index ->
+                    if (lights.isNotEmpty()) {
+                        items(lights.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.lights)
-                            SetEntityUI(lightsRemembered[index], index)
+                            SetEntityUI(lights[index], index)
                         }
                     }
-                    if (scenesRemembered.isNotEmpty()) {
-                        items(scenesRemembered.size) { index ->
+                    if (scenes.isNotEmpty()) {
+                        items(scenes.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.scenes)
 
-                            SetEntityUI(scenesRemembered[index], index)
+                            SetEntityUI(scenes[index], index)
                         }
                     }
-                    if (scriptsRemembered.isNotEmpty()) {
-                        items(scriptsRemembered.size) { index ->
+                    if (scripts.isNotEmpty()) {
+                        items(scripts.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.scripts)
-                            SetEntityUI(scriptsRemembered[index], index)
+                            SetEntityUI(scripts[index], index)
                         }
                     }
-                    if (switchesRemembered.isNotEmpty()) {
-                        items(switchesRemembered.size) { index ->
+                    if (switches.isNotEmpty()) {
+                        items(switches.size) { index ->
                             if (index == 0)
                                 SetTitle(R.string.switches)
-                            SetEntityUI(switchesRemembered[index], index)
+                            SetEntityUI(switches[index], index)
                         }
                     }
 
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
index 25d748f45b4..7e89709d796 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
@@ -8,6 +8,4 @@ interface HomePresenter {
     fun onEntityClicked(entity: Entity<Any>)
     fun onLogoutClicked()
     fun onFinish()
-
-    suspend fun getEntities(): Array<Entity<Any>>
 }
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
index 87cdc3fcf9f..7f85beb7490 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
@@ -47,15 +47,6 @@ class HomePresenterImpl @Inject constructor(
         return isRegistered
     }
 
-    override suspend fun getEntities(): Array<Entity<Any>> {
-        return try {
-            integrationUseCase.getEntities()
-        } catch (e: Exception) {
-            Log.e(TAG, "Unable to get entities", e)
-            emptyArray()
-        }
-    }
-
     override fun onEntityClicked(entity: Entity<Any>) {
 
         if (entity.entityId.split(".")[0] in toggleDomains) {
diff --git a/wear/src/main/java/io/homeassistant/companion/android/viewModels/EntityViewModel.kt b/wear/src/main/java/io/homeassistant/companion/android/viewModels/EntityViewModel.kt
new file mode 100755
index 00000000000..d703d9b2582
--- /dev/null
+++ b/wear/src/main/java/io/homeassistant/companion/android/viewModels/EntityViewModel.kt
@@ -0,0 +1,41 @@
+package io.homeassistant.companion.android.viewModels
+
+import android.content.Context
+import android.util.Log
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import io.homeassistant.companion.android.common.dagger.GraphComponentAccessor
+import io.homeassistant.companion.android.common.data.integration.Entity
+import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+class EntityViewModel : ViewModel() {
+
+    @Inject
+    lateinit var integrationUseCase: IntegrationRepository
+
+    var entitiesResponse: Array<Entity<Any>> by mutableStateOf(arrayOf())
+
+    companion object {
+        private const val TAG = "EntityViewModel"
+    }
+
+    fun getEntities(context: Context) {
+        DaggerViewModuleComponent.builder()
+            .appComponent((context as GraphComponentAccessor).appComponent)
+            .build()
+            .inject(this)
+        viewModelScope.launch {
+            try {
+                val entities = integrationUseCase.getEntities()
+                entitiesResponse = entities
+            } catch (e: Exception) {
+                Log.e(TAG, "Unable to get list of entities", e)
+            }
+        }
+    }
+}
diff --git a/wear/src/main/java/io/homeassistant/companion/android/viewModels/ViewModuleComponent.kt b/wear/src/main/java/io/homeassistant/companion/android/viewModels/ViewModuleComponent.kt
new file mode 100755
index 00000000000..01255428438
--- /dev/null
+++ b/wear/src/main/java/io/homeassistant/companion/android/viewModels/ViewModuleComponent.kt
@@ -0,0 +1,10 @@
+package io.homeassistant.companion.android.viewModels
+
+import dagger.Component
+import io.homeassistant.companion.android.common.dagger.AppComponent
+
+@Component(dependencies = [AppComponent::class])
+interface ViewModuleComponent {
+
+    fun inject(entityViewModel: EntityViewModel)
+}

From 3d70346460c54e20a4d46f077e3e129247e8702e Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Mon, 1 Nov 2021 15:52:09 -0700
Subject: [PATCH 10/11] Restore onViewReady changes

---
 .../homeassistant/companion/android/home/HomeActivity.kt | 9 ++++-----
 .../companion/android/home/HomePresenter.kt              | 2 +-
 .../companion/android/home/HomePresenterImpl.kt          | 8 ++------
 3 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 58b6632ada6..019bf2ef13c 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -69,11 +69,10 @@ class HomeActivity : ComponentActivity(), HomeView {
             .build()
             .inject(this)
 
-        if (presenter.onViewReady()) {
-            setContent {
-                LoadHomePage(entities = entityViewModel.entitiesResponse)
-                entityViewModel.getEntities(applicationContext)
-            }
+        presenter.onViewReady()
+        setContent {
+            LoadHomePage(entities = entityViewModel.entitiesResponse)
+            entityViewModel.getEntities(applicationContext)
         }
     }
 
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
index 7e89709d796..8cf1a229e9a 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenter.kt
@@ -4,7 +4,7 @@ import io.homeassistant.companion.android.common.data.integration.Entity
 
 interface HomePresenter {
 
-    fun onViewReady(): Boolean
+    fun onViewReady()
     fun onEntityClicked(entity: Entity<Any>)
     fun onLogoutClicked()
     fun onFinish()
diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
index 7f85beb7490..fb3c69cc007 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomePresenterImpl.kt
@@ -12,7 +12,6 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
 import javax.inject.Inject
 
 class HomePresenterImpl @Inject constructor(
@@ -31,20 +30,17 @@ class HomePresenterImpl @Inject constructor(
 
     private val mainScope: CoroutineScope = CoroutineScope(Dispatchers.Main + Job())
 
-    override fun onViewReady(): Boolean {
-        var isRegistered = false
-        runBlocking {
+    override fun onViewReady() {
+        mainScope.launch {
             val sessionValid = authenticationUseCase.getSessionState() == SessionState.CONNECTED
             if (sessionValid && integrationUseCase.isRegistered()) {
                 resyncRegistration()
-                isRegistered = true
             } else if (sessionValid) {
                 view.displayMobileAppIntegration()
             } else {
                 view.displayOnBoarding()
             }
         }
-        return isRegistered
     }
 
     override fun onEntityClicked(entity: Entity<Any>) {

From a83ba1212c0298e4e7b51a33bb1aea516d79c540 Mon Sep 17 00:00:00 2001
From: Daniel Shokouhi <dshokouhi@gmail.com>
Date: Mon, 1 Nov 2021 21:24:23 -0700
Subject: [PATCH 11/11] Add a loading screen while waiting on viewmodel

---
 .../companion/android/home/HomeActivity.kt    | 195 ++++++++++--------
 wear/src/main/res/values/strings.xml          |   1 +
 2 files changed, 115 insertions(+), 81 deletions(-)

diff --git a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
index 019bf2ef13c..1c42b6523b8 100644
--- a/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
+++ b/wear/src/main/java/io/homeassistant/companion/android/home/HomeActivity.kt
@@ -8,6 +8,7 @@ import androidx.activity.compose.setContent
 import androidx.activity.viewModels
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
@@ -23,6 +24,7 @@ import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.wear.compose.material.Chip
+import androidx.wear.compose.material.ChipColors
 import androidx.wear.compose.material.ChipDefaults
 import androidx.wear.compose.material.MaterialTheme
 import androidx.wear.compose.material.PositionIndicator
@@ -49,7 +51,7 @@ class HomeActivity : ComponentActivity(), HomeView {
     @Inject
     lateinit var presenter: HomePresenter
 
-    val entityViewModel by viewModels<EntityViewModel>()
+    private val entityViewModel by viewModels<EntityViewModel>()
 
     companion object {
         private const val TAG = "HomeActivity"
@@ -96,96 +98,119 @@ class HomeActivity : ComponentActivity(), HomeView {
     @Composable
     private fun LoadHomePage(entities: Array<Entity<Any>>) {
 
-        val scenes =
-            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "scene" }
-        val scripts =
-            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "script" }
-        val lights =
-            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "light" }
-        val inputBooleans = entities.sortedBy { it.entityId }
-            .filter { it.entityId.split(".")[0] == "input_boolean" }
-        val switches =
-            entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "switch" }
-
-        val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState()
-
-        MaterialTheme {
-            Scaffold(
-                positionIndicator = {
-                    if (scalingLazyListState.isScrollInProgress)
-                        PositionIndicator(scalingLazyListState = scalingLazyListState)
-                }
-            ) {
-                ScalingLazyColumn(
+        if (entities.isNullOrEmpty()) {
+            Column {
+                Spacer(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .padding(top = 10.dp)
+                )
+                SetTitle(id = R.string.loading)
+                Chip(
                     modifier = Modifier
-                        .fillMaxSize(),
-                    contentPadding = PaddingValues(
-                        top = 10.dp,
-                        start = 10.dp,
-                        end = 10.dp,
-                        bottom = 40.dp
-                    ),
-                    horizontalAlignment = Alignment.CenterHorizontally,
-                    state = scalingLazyListState
+                        .padding(top = 50.dp, start = 10.dp, end = 10.dp),
+                    label = {
+                        Text(
+                            text = stringResource(R.string.loading_entities),
+                            textAlign = TextAlign.Center
+                        )
+                    },
+                    onClick = { /* No op */ },
+                    colors = setChipDefaults()
+                )
+            }
+        } else {
+            val scenes =
+                entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "scene" }
+            val scripts =
+                entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "script" }
+            val lights =
+                entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "light" }
+            val inputBooleans = entities.sortedBy { it.entityId }
+                .filter { it.entityId.split(".")[0] == "input_boolean" }
+            val switches =
+                entities.sortedBy { it.entityId }.filter { it.entityId.split(".")[0] == "switch" }
+
+            val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState()
+
+            MaterialTheme {
+                Scaffold(
+                    positionIndicator = {
+                        if (scalingLazyListState.isScrollInProgress)
+                            PositionIndicator(scalingLazyListState = scalingLazyListState)
+                    }
                 ) {
-                    if (inputBooleans.isNotEmpty()) {
-                        items(inputBooleans.size) { index ->
-                            if (index == 0)
-                                SetTitle(R.string.input_booleans)
-                            SetEntityUI(inputBooleans[index], index)
+                    ScalingLazyColumn(
+                        modifier = Modifier
+                            .fillMaxSize(),
+                        contentPadding = PaddingValues(
+                            top = 10.dp,
+                            start = 10.dp,
+                            end = 10.dp,
+                            bottom = 40.dp
+                        ),
+                        horizontalAlignment = Alignment.CenterHorizontally,
+                        state = scalingLazyListState
+                    ) {
+                        if (inputBooleans.isNotEmpty()) {
+                            items(inputBooleans.size) { index ->
+                                if (index == 0)
+                                    SetTitle(R.string.input_booleans)
+                                SetEntityUI(inputBooleans[index], index)
+                            }
                         }
-                    }
-                    if (lights.isNotEmpty()) {
-                        items(lights.size) { index ->
-                            if (index == 0)
-                                SetTitle(R.string.lights)
-                            SetEntityUI(lights[index], index)
+                        if (lights.isNotEmpty()) {
+                            items(lights.size) { index ->
+                                if (index == 0)
+                                    SetTitle(R.string.lights)
+                                SetEntityUI(lights[index], index)
+                            }
                         }
-                    }
-                    if (scenes.isNotEmpty()) {
-                        items(scenes.size) { index ->
-                            if (index == 0)
-                                SetTitle(R.string.scenes)
+                        if (scenes.isNotEmpty()) {
+                            items(scenes.size) { index ->
+                                if (index == 0)
+                                    SetTitle(R.string.scenes)
 
-                            SetEntityUI(scenes[index], index)
+                                SetEntityUI(scenes[index], index)
+                            }
                         }
-                    }
-                    if (scripts.isNotEmpty()) {
-                        items(scripts.size) { index ->
-                            if (index == 0)
-                                SetTitle(R.string.scripts)
-                            SetEntityUI(scripts[index], index)
+                        if (scripts.isNotEmpty()) {
+                            items(scripts.size) { index ->
+                                if (index == 0)
+                                    SetTitle(R.string.scripts)
+                                SetEntityUI(scripts[index], index)
+                            }
                         }
-                    }
-                    if (switches.isNotEmpty()) {
-                        items(switches.size) { index ->
-                            if (index == 0)
-                                SetTitle(R.string.switches)
-                            SetEntityUI(switches[index], index)
+                        if (switches.isNotEmpty()) {
+                            items(switches.size) { index ->
+                                if (index == 0)
+                                    SetTitle(R.string.switches)
+                                SetEntityUI(switches[index], index)
+                            }
                         }
-                    }
 
-                    item {
-                        Column {
-                            SetTitle(R.string.other)
-                            Chip(
-                                modifier = Modifier
-                                    .fillMaxWidth()
-                                    .padding(top = 10.dp),
-                                icon = {
-                                    Image(asset = CommunityMaterial.Icon.cmd_exit_run)
-                                },
-                                label = {
-                                    Text(
-                                        text = stringResource(id = R.string.logout)
+                        item {
+                            Column {
+                                SetTitle(R.string.other)
+                                Chip(
+                                    modifier = Modifier
+                                        .fillMaxWidth()
+                                        .padding(top = 10.dp),
+                                    icon = {
+                                        Image(asset = CommunityMaterial.Icon.cmd_exit_run)
+                                    },
+                                    label = {
+                                        Text(
+                                            text = stringResource(id = R.string.logout)
+                                        )
+                                    },
+                                    onClick = { presenter.onLogoutClicked() },
+                                    colors = ChipDefaults.primaryChipColors(
+                                        backgroundColor = Color.Red,
+                                        contentColor = Color.Black
                                     )
-                                },
-                                onClick = { presenter.onLogoutClicked() },
-                                colors = ChipDefaults.primaryChipColors(
-                                    backgroundColor = Color.Red,
-                                    contentColor = Color.Black
                                 )
-                            )
+                            }
                         }
                     }
                 }
@@ -228,7 +253,7 @@ class HomeActivity : ComponentActivity(), HomeView {
                 )
             },
             onClick = { presenter.onEntityClicked(entity) },
-            colors = ChipDefaults.primaryChipColors(backgroundColor = colorResource(id = R.color.colorAccent), contentColor = Color.Black)
+            colors = setChipDefaults()
         )
     }
 
@@ -243,4 +268,12 @@ class HomeActivity : ComponentActivity(), HomeView {
                 .fillMaxWidth()
         )
     }
+
+    @Composable
+    private fun setChipDefaults(): ChipColors {
+        return ChipDefaults.primaryChipColors(
+            backgroundColor = colorResource(id = R.color.colorAccent),
+            contentColor = Color.Black
+        )
+    }
 }
diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml
index 57bad2b4db1..d94b729a521 100644
--- a/wear/src/main/res/values/strings.xml
+++ b/wear/src/main/res/values/strings.xml
@@ -33,4 +33,5 @@
     <string name="lights">Lights</string>
     <string name="input_booleans">Input Booleans</string>
     <string name="switches">Switches</string>
+    <string name="loading_entities">Please wait while we load your entities</string>
 </resources>
\ No newline at end of file