diff --git a/app/src/main/kotlin/io/homeassistant/companion/android/noconnection/NoConnectionActivity.kt b/app/src/main/kotlin/io/homeassistant/companion/android/noconnection/NoConnectionActivity.kt
new file mode 100644
index 00000000000..8fa21ae3049
--- /dev/null
+++ b/app/src/main/kotlin/io/homeassistant/companion/android/noconnection/NoConnectionActivity.kt
@@ -0,0 +1,321 @@
+package io.homeassistant.companion.android.noconnection
+
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.Icon
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.OutlinedButton
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Refresh
+import androidx.compose.material.icons.filled.Settings
+import androidx.compose.material.icons.outlined.Newspaper
+import androidx.compose.material.icons.outlined.WifiOff
+import androidx.compose.material.icons.rounded.KeyboardArrowDown
+import androidx.compose.material.icons.rounded.KeyboardArrowUp
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import io.homeassistant.companion.android.BaseActivity
+import io.homeassistant.companion.android.R
+import io.homeassistant.companion.android.common.R as commonR
+import io.homeassistant.companion.android.util.compose.HomeAssistantAppTheme
+
+class NoConnectionActivity : BaseActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+
+ setContent {
+ HomeAssistantAppTheme {
+ NoConnectionScreen()
+ }
+ }
+ }
+}
+
+@Composable
+fun NoConnectionScreen() {
+ Column(
+ modifier = Modifier
+ .verticalScroll(rememberScrollState())
+ ) {
+ Header()
+ Content()
+ }
+}
+
+@Composable
+fun Header() {
+ Surface(
+ color = MaterialTheme.colors.primary,
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(180.dp)
+ ) {
+ Box(
+ modifier = Modifier
+ .wrapContentWidth()
+ .wrapContentHeight()
+ ) {
+ Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.app_icon_launch),
+ contentDescription = "",
+ tint = Color.White,
+ modifier = Modifier.align(Alignment.Center)
+ )
+
+ // TODO check Badge component
+ Icon(
+ imageVector = Icons.Outlined.WifiOff,
+ contentDescription = "",
+ modifier = Modifier
+ .align(Alignment.TopEnd)
+ .offset(y = 18.dp, x = -(13.dp))
+ .shadow(elevation = 8.dp, shape = CircleShape) // Added shadow her
+ .background(Color.White)
+ .padding(4.dp),
+ tint = Color.Red
+ )
+ }
+ }
+}
+
+@Composable
+fun Content() {
+ Column(
+ modifier = Modifier
+ .fillMaxHeight()
+ .padding(16.dp),
+ ) {
+ Column {
+ // Title
+ Text(
+ text = stringResource(commonR.string.error_connection_failed),
+ style = MaterialTheme.typography.h4,
+ fontWeight = FontWeight.Bold,
+ )
+ // Description
+ Text(
+ text = stringResource(commonR.string.webview_error),
+ style = MaterialTheme.typography.body1,
+ modifier = Modifier.padding(top = 16.dp)
+ )
+ // Connection info
+ Surface(
+ shape = MaterialTheme.shapes.small,
+ color = colorBackground,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp)
+ ) {
+ Column(modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally) {
+ Text("The app is currently connecting to")
+ Text("http://127.0.0.1:8123", style = MaterialTheme.typography.caption, fontWeight = FontWeight.Bold, color = Color.Blue)
+ }
+ }
+
+ MoreDetails()
+ SupportUs()
+ Action()
+ }
+ GetHelp()
+ }
+}
+
+@Composable
+private fun ColumnScope.GetHelp() {
+ Text(text = "Get some help from the community", modifier = Modifier.fillMaxWidth().padding(top = 24.dp), textAlign = TextAlign.Center)
+ Row(
+ modifier = Modifier
+ .padding(top = 8.dp, bottom = 16.dp)
+ .fillMaxWidth()
+ .align(Alignment.CenterHorizontally),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ val buttonModifier = Modifier
+ .padding(horizontal = 10.dp) // Add padding between buttons
+ .size(48.dp) // Set the size for all buttons
+
+ OutlinedButton(onClick = { /*TODO*/ }, modifier = buttonModifier) {
+ Icon(imageVector = Icons.Outlined.Newspaper, contentDescription = "Documentation", modifier = Modifier.size(24.dp))
+ }
+ OutlinedButton(onClick = { /*TODO*/ }, modifier = buttonModifier) {
+ Icon(imageVector = ImageVector.vectorResource(R.drawable.discord), contentDescription = "Home Assistant Discord", modifier = Modifier.size(24.dp))
+ }
+ OutlinedButton(onClick = { /*TODO*/ }, modifier = buttonModifier) {
+ Icon(imageVector = ImageVector.vectorResource(R.drawable.github), contentDescription = "Github Android Companion app", modifier = Modifier.size(24.dp))
+ }
+ }
+}
+
+@Composable
+private fun MoreDetails(defaultExpanded: Boolean = false) {
+ ExpandableSection(title = "More details", modifier = Modifier.padding(top = 16.dp), defaultExpanded = defaultExpanded) {
+ Column(modifier = Modifier.padding(start = 16.dp, bottom = 16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
+ Text("Description", style = MaterialTheme.typography.h6)
+ Text("Could not connect to the server")
+
+ Text("Error", style = MaterialTheme.typography.h6)
+ Text("IllegalStateException")
+ }
+ }
+}
+
+@Composable
+private fun ColumnScope.Action() {
+ Row(
+ modifier = Modifier
+ .align(Alignment.CenterHorizontally)
+ .padding(top = 16.dp),
+ horizontalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterHorizontally)
+ ) {
+ OutlinedButton(
+ onClick = { /*TODO*/ },
+ modifier = Modifier.padding(horizontal = 16.dp)
+ ) {
+ Icon(imageVector = Icons.Filled.Refresh, contentDescription = "")
+ // TODO auto retry
+ Text("Retry")
+ }
+ OutlinedButton(
+ onClick = { /*TODO*/ },
+ modifier = Modifier.padding(horizontal = 16.dp)
+ ) {
+ Icon(imageVector = Icons.Filled.Settings, contentDescription = "")
+ Text("Open Settings")
+ }
+ }
+}
+
+@Composable
+private fun SupportUs() {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp)
+ .clip(MaterialTheme.shapes.small)
+ .background(colorBackground)
+ ) {
+ // val text = "It seems that you cannot reach home for some reason. Did you consider using supporting Nabu Casa? It would also give you access to your home from everywhere."
+ val text = "If you'd like secure access end to end encrypted to your home from anywhere while supporting the Home Assistant project, consider using"
+ Text(
+ text = text,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ textAlign = TextAlign.Start,
+ style = MaterialTheme.typography.body2
+ )
+ Image(
+ imageVector = ImageVector.vectorResource(R.drawable.nabucasa),
+ contentDescription = "Nabu casa",
+ modifier = Modifier
+ .align(Alignment.CenterHorizontally)
+ .height(40.dp)
+ .padding(bottom = 16.dp)
+ )
+ }
+}
+
+@Composable
+fun ExpandableSectionTitle(modifier: Modifier = Modifier, isExpanded: Boolean, title: String) {
+ val icon = if (isExpanded) Icons.Rounded.KeyboardArrowUp else Icons.Rounded.KeyboardArrowDown
+
+ Row(modifier = modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically) {
+ Text(
+ text = title,
+ style = MaterialTheme.typography.body1,
+ modifier = Modifier
+ .weight(1f)
+ .padding(start = 8.dp)
+ )
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = icon,
+ tint = MaterialTheme.colors.primary,
+ contentDescription = "Open/Close detail"
+ )
+ }
+}
+
+private val colorBackground = Color(0xFFF0F0F0)
+
+@Composable
+fun ExpandableSection(
+ title: String,
+ modifier: Modifier = Modifier,
+ defaultExpanded: Boolean = false,
+ content: @Composable () -> Unit
+) {
+ var isExpanded by rememberSaveable { mutableStateOf(defaultExpanded) }
+ Column(
+ modifier = modifier
+ .clickable { isExpanded = !isExpanded }
+ .clip(MaterialTheme.shapes.small)
+ .background(color = colorBackground)
+ .fillMaxWidth()
+ ) {
+ ExpandableSectionTitle(isExpanded = isExpanded, title = title)
+
+ AnimatedVisibility(
+ modifier = Modifier
+ .background(colorBackground)
+ .fillMaxWidth(),
+ visible = isExpanded
+ ) {
+ content()
+ }
+ }
+}
+
+@Preview
+@Composable
+fun NoConnectionScreenPreview() {
+ HomeAssistantAppTheme {
+ NoConnectionScreen()
+ }
+}
+
+@Preview
+@Composable
+private fun MoreDetailsPreview() {
+ MoreDetails(true)
+}
diff --git a/app/src/main/res/drawable/discord.xml b/app/src/main/res/drawable/discord.xml
new file mode 100644
index 00000000000..da85881bb21
--- /dev/null
+++ b/app/src/main/res/drawable/discord.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/github.xml b/app/src/main/res/drawable/github.xml
new file mode 100644
index 00000000000..34241eaa3cd
--- /dev/null
+++ b/app/src/main/res/drawable/github.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/nabucasa.xml b/app/src/main/res/drawable/nabucasa.xml
new file mode 100644
index 00000000000..859c2d08b1a
--- /dev/null
+++ b/app/src/main/res/drawable/nabucasa.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+