Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8ea4572
Migrate template widget configuration to Compose and Material3
su7ri Aug 1, 2026
650e675
Disable the action button while a new template render is in flight
su7ri Aug 1, 2026
cd70cee
Merge branch 'main' into compose-template-widget-6304
su7ri Aug 1, 2026
b2d06f5
Address review: screenshot test, isBlank, shared parseHtml util, prev…
su7ri Aug 2, 2026
91868ae
Add reference screenshots for TemplateWidgetConfigureScreen
su7ri Aug 2, 2026
e440398
Wrap TemplateSection's children in a Column to emit from a single source
claude Aug 2, 2026
0daa207
Fix preview card icon/text colors in dark mode
su7ri Aug 4, 2026
8c80041
Add unit tests for parseHtml
claude Aug 4, 2026
e578ca5
Address remaining review feedback on TemplateWidgetConfigureScreen
claude Aug 4, 2026
bc72086
Move private constants to the top of their files
claude Aug 4, 2026
c0a1e5e
Avoid re-parsing the rendered preview and gate saving on a valid text…
claude Aug 4, 2026
d3c5165
Move private ViewModel members to file conventions
claude Aug 4, 2026
71d3de4
Drop unnecessary internal modifier on onTextColorSelected
claude Aug 4, 2026
7b81b8b
Address remaining TimoPtr comments: visibility, tests, screenshots
claude Aug 4, 2026
79dc55d
Move test states to top-level private vals
su7ri Aug 6, 2026
b37a35f
Merge branch 'main' into compose-template-widget-6304
su7ri Aug 6, 2026
e33d63a
Merge branch 'main' into compose-template-widget-6304
su7ri Aug 9, 2026
63a2baf
Update reference screenshots for TemplateWidgetConfigureScreen
su7ri Aug 14, 2026
248c6a2
Merge branch 'compose-template-widget-6304' of https://github.com/su7…
su7ri Aug 14, 2026
6ef896f
Reuse empty template screenshot test for single-server case
su7ri Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
package io.homeassistant.companion.android.settings.wear.views

import android.graphics.Typeface
import android.text.style.AbsoluteSizeSpan
import android.text.style.CharacterStyle
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.text.style.StyleSpan
import android.text.style.UnderlineSpan
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand All @@ -26,24 +19,17 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY
import androidx.core.text.HtmlCompat.fromHtml
import com.mikepenz.iconics.compose.Image
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import io.homeassistant.companion.android.common.R as commonR
import io.homeassistant.companion.android.util.compose.parseHtml
import io.homeassistant.companion.android.util.intervalToString
import io.homeassistant.companion.android.util.safeBottomPaddingValues

Expand Down Expand Up @@ -130,35 +116,6 @@ fun SettingsWearTemplateTile(
}
}

private fun parseHtml(renderedText: String) = buildAnnotatedString {
// Replace control char \r\n, \r, \n and also \r\n, \r, \n as text literals in strings to <br>
val renderedSpanned =
fromHtml(renderedText.replace("(\r\n|\r|\n)|(\\\\r\\\\n|\\\\r|\\\\n)".toRegex(), "<br>"), FROM_HTML_MODE_LEGACY)
append(renderedSpanned.toString())
renderedSpanned.getSpans(0, renderedSpanned.length, CharacterStyle::class.java).forEach { span ->
val start = renderedSpanned.getSpanStart(span)
val end = renderedSpanned.getSpanEnd(span)
when (span) {
is AbsoluteSizeSpan -> addStyle(SpanStyle(fontSize = span.size.sp), start, end)
is ForegroundColorSpan -> addStyle(SpanStyle(color = Color(span.foregroundColor)), start, end)
is RelativeSizeSpan -> {
val defaultSize = 12
addStyle(SpanStyle(fontSize = (span.sizeChange * defaultSize).sp), start, end)
}
is StyleSpan -> when (span.style) {
Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)
Typeface.ITALIC -> addStyle(SpanStyle(fontStyle = FontStyle.Italic), start, end)
Typeface.BOLD_ITALIC -> addStyle(
SpanStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic),
start,
end,
)
}
is UnderlineSpan -> addStyle(SpanStyle(textDecoration = TextDecoration.Underline), start, end)
}
}
}

@Preview
@Composable
private fun PreviewSettingsWearTemplateTile() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.homeassistant.companion.android.util.compose

import android.graphics.Typeface
import android.text.style.AbsoluteSizeSpan
import android.text.style.CharacterStyle
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.text.style.StyleSpan
import android.text.style.UnderlineSpan
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.sp
import androidx.core.text.HtmlCompat

private val LINE_BREAK_REGEX = "(\r\n|\r|\n)|(\\\\r\\\\n|\\\\r|\\\\n)".toRegex()
private const val DEFAULT_RELATIVE_SIZE_SP = 12

/**
* Converts HTML, as returned by a rendered Home Assistant template, into an [AnnotatedString] by
* translating the [android.text.Spanned] styles produced by [HtmlCompat.fromHtml] into Compose
* [SpanStyle]s. Shared by every screen that displays a rendered template.
*/
fun parseHtml(renderedText: String): AnnotatedString = buildAnnotatedString {
Comment thread
su7ri marked this conversation as resolved.
// Replace both actual and literal (escaped) line break characters with <br>
val renderedSpanned = HtmlCompat.fromHtml(
renderedText.replace(LINE_BREAK_REGEX, "<br>"),
HtmlCompat.FROM_HTML_MODE_LEGACY,
)
append(renderedSpanned.toString())
renderedSpanned.getSpans(0, renderedSpanned.length, CharacterStyle::class.java).forEach { span ->
val start = renderedSpanned.getSpanStart(span)
val end = renderedSpanned.getSpanEnd(span)
when (span) {
is AbsoluteSizeSpan -> addStyle(SpanStyle(fontSize = span.size.sp), start, end)
is ForegroundColorSpan -> addStyle(SpanStyle(color = Color(span.foregroundColor)), start, end)
is RelativeSizeSpan -> {
addStyle(SpanStyle(fontSize = (span.sizeChange * DEFAULT_RELATIVE_SIZE_SP).sp), start, end)
}
is StyleSpan -> when (span.style) {
Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)
Typeface.ITALIC -> addStyle(SpanStyle(fontStyle = FontStyle.Italic), start, end)
Typeface.BOLD_ITALIC -> addStyle(
SpanStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic),
start,
end,
)
}
is UnderlineSpan -> addStyle(SpanStyle(textDecoration = TextDecoration.Underline), start, end)
}
}
}
Loading
Loading