Skip to content

Migrate entity widget configuration to Compose#7007

Draft
himu-gupta wants to merge 9 commits into
home-assistant:mainfrom
himu-gupta:feat/entity-widget-compose
Draft

Migrate entity widget configuration to Compose#7007
himu-gupta wants to merge 9 commits into
home-assistant:mainfrom
himu-gupta:feat/entity-widget-compose

Conversation

@himu-gupta

@himu-gupta himu-gupta commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • migrate EntityWidgetConfigureActivity from XML views to Compose and Home Assistant Material 3 components
  • move configuration state, validation, creation, and update persistence into an assisted ViewModel
  • preserve server selection, custom attributes, tap actions, widget themes, text colors, and existing widget values
  • add focused ViewModel tests for restoration, recreation, persistence, and server changes

Closes #6307

Screenshots

Light Dark Review feedback state
Entity widget configuration in light mode Entity widget configuration in dark mode Entity widget configuration with server picker and attributes expanded

Server picker fix

Entity widget configuration server picker in dark mode with selected entity

Testing

  • ./gradlew --no-daemon --console=plain :build-logic:convention:ktlintFormat ktlintFormat
  • ./gradlew --no-daemon --console=plain :app:testFullDebugUnitTest --tests io.homeassistant.companion.android.widgets.entity.EntityWidgetConfigureViewModelTest

@home-assistant home-assistant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @himu-gupta

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

@himu-gupta
himu-gupta marked this pull request as ready for review June 12, 2026 00:31
Copilot AI review requested due to automatic review settings June 12, 2026 00:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Migrates the Entity widget configuration UI from the legacy XML/ViewBinding implementation to a Jetpack Compose-based screen backed by a new ViewModel, and adds unit tests for key configuration behaviors.

Changes:

  • Replaced EntityWidgetConfigureActivity’s legacy view logic with Compose UI and a dedicated EntityWidgetConfigureViewModel.
  • Added a Compose configuration screen with attribute selection UI (including custom attribute entry).
  • Added unit tests for restoring/persisting widget configuration and handling server changes.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
common/src/main/res/values/strings.xml Adds a new string resource used by the Compose attribute picker UI.
app/src/test/kotlin/io/homeassistant/companion/android/widgets/entity/EntityWidgetConfigureViewModelTest.kt Introduces unit tests for the new configuration ViewModel behavior.
app/src/main/res/layout/widget_static_configure.xml Removes the legacy XML layout now replaced by Compose UI.
app/src/main/kotlin/io/homeassistant/companion/android/widgets/entity/EntityWidgetConfigureViewModel.kt Adds a new ViewModel managing widget configuration state, persistence, and pin flow.
app/src/main/kotlin/io/homeassistant/companion/android/widgets/entity/EntityWidgetConfigureScreen.kt Adds the Compose configuration UI (server/entity pickers, attributes, separators, styling options).
app/src/main/kotlin/io/homeassistant/companion/android/widgets/entity/EntityWidgetConfigureActivity.kt Updates the activity to host Compose UI and delegate configuration actions to the ViewModel.

@himu-gupta

Copy link
Copy Markdown
Contributor Author

The CLA check is now passing, but the original Home Assistant CLA bot review still shows Changes requested and keeps the PR in a blocked state. Could a maintainer please dismiss the stale review when convenient? All review threads are resolved, the branch is rebased onto the latest main, and the focused tests, ktlint, and full debug build pass.

@himu-gupta

Copy link
Copy Markdown
Contributor Author

Hi @himu-gupta

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

CLA was signed.

@TimoPtr

TimoPtr commented Jun 15, 2026

Copy link
Copy Markdown
Member

Could you update the PR description to add screenshots, thanks.

@himu-gupta

Copy link
Copy Markdown
Contributor Author

Added light and dark screenshots to the PR description.

@TimoPtr

TimoPtr commented Jun 18, 2026

Copy link
Copy Markdown
Member

The UI does already look much better than from the old one.

image

Things to address

  • Should be centered
  • The picker should be aligned with the size of the inputs
  • Clicking Append attributes could animate nicely the hidden field
  • The Attributemenu could/should be merge with the Add attribute input, to improve the UX
  • Changing the entity selected doesn't update the label anymore
  • Server picker is using the old style
image

Things to change/discuss

  • Update widget button logic should be improved (in another PR), to include validation on inputs today you can input a huge number for instance in the Widget text size.
  • We could add a top left close button in the topbar

@TimoPtr
TimoPtr marked this pull request as draft June 18, 2026 12:48

@TimoPtr TimoPtr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a first very quick review of the code to identify the missing bits.

Shaan-alpha added a commit to Shaan-alpha/android that referenced this pull request Jun 18, 2026
…n system

Address review feedback by aligning the Media Player Controls widget
configuration screen with the Compose pattern used in home-assistant#7007.

- Add MediaPlayerControlsWidgetConfigureViewModel exposing an immutable
  ViewState, with server/entity/registry flows and a Snackbar message
  channel; the Activity is now a thin BaseActivity that delegates to it
- Add unit tests for the ViewModel (MainDispatcherJUnit5Extension)
- Use HATheme + Material 3 throughout to fix the broken dark/light colors
- Replace the free-text entity field with EntityPicker, providing the
  entity/device/area registries for friendlier names
- Surface widget create/update errors via Snackbar instead of Toast
- Split the screen into smaller composables and use HaDimens for spacing
- Proper HACheckbox row click, full-width inputs and action button, and a
  top-left close button
- Regenerate screenshot reference images for the new UI

Note: EntityPicker is single-select, so the widget now stores a single
media_player entity instead of the previous comma-separated list.
Shaan-alpha added a commit to Shaan-alpha/android that referenced this pull request Jun 18, 2026
…n system

Address review feedback by aligning the Media Player Controls widget
configuration screen with the Compose pattern used in home-assistant#7007.

- Add MediaPlayerControlsWidgetConfigureViewModel exposing an immutable
  ViewState, with server/entity/registry flows and a Snackbar message
  channel; the Activity is now a thin BaseActivity that delegates to it
- Add unit tests for the ViewModel (MainDispatcherJUnit5Extension)
- Use HATheme + Material 3 throughout to fix the broken dark/light colors
- Replace the free-text entity field with EntityPicker, providing the
  entity/device/area registries for friendlier names
- Surface widget create/update errors via Snackbar instead of Toast
- Split the screen into smaller composables and use HaDimens for spacing
- Proper HACheckbox row click, full-width inputs and action button, and a
  top-left close button
- Regenerate screenshot reference images for the new UI

Note: EntityPicker is single-select, so the widget now stores a single
media_player entity instead of the previous comma-separated list.
Shaan-alpha added a commit to Shaan-alpha/android that referenced this pull request Jun 19, 2026
…n system

Address review feedback by aligning the Media Player Controls widget
configuration screen with the Compose pattern used in home-assistant#7007.

- Add MediaPlayerControlsWidgetConfigureViewModel exposing an immutable
  ViewState, with server/entity/registry flows and a Snackbar message
  channel; the Activity is now a thin BaseActivity that delegates to it
- Add unit tests for the ViewModel (MainDispatcherJUnit5Extension)
- Use HATheme + Material 3 throughout to fix the broken dark/light colors
- Replace the free-text entity field with EntityPicker, providing the
  entity/device/area registries for friendlier names
- Surface widget create/update errors via Snackbar instead of Toast
- Split the screen into smaller composables and use HaDimens for spacing
- Proper HACheckbox row click, full-width inputs and action button, and a
  top-left close button
- Regenerate screenshot reference images for the new UI

Note: EntityPicker is single-select, so the widget now stores a single
media_player entity instead of the previous comma-separated list.
@himu-gupta
himu-gupta force-pushed the feat/entity-widget-compose branch from 218f3fd to eca4235 Compare June 20, 2026 19:55
@himu-gupta

Copy link
Copy Markdown
Contributor Author

Added a review-feedback screenshot to the PR description showing the updated centered form with the modern server picker and append-attributes section expanded, including the merged Add attribute input/chips and entity-derived label.

@himu-gupta

Copy link
Copy Markdown
Contributor Author

Added a dedicated server picker fix screenshot to the PR description. This one matches the dark top-of-screen state from your attached image: the server picker now uses the HA dropdown style and is aligned with the selected entity picker.

@himu-gupta
himu-gupta marked this pull request as ready for review June 21, 2026 14:12
@himu-gupta
himu-gupta force-pushed the feat/entity-widget-compose branch from c2c3670 to e483268 Compare June 21, 2026 15:11
@TimoPtr

TimoPtr commented Jun 23, 2026

Copy link
Copy Markdown
Member

I think we could remove the "Append attribute value" checkbox by only showing the tags to pick. Does it make sense to even allow custom attributes? @jpelgrom wdyt

@TimoPtr TimoPtr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to let you know that we don't allow usage of autonomous agent, take the time to look at all my comments.

get() = intent.extras?.getBoolean(ManageWidgetsViewModel.CONFIGURE_REQUEST_LAUNCHER, false) == true

override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdgeCompat()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
enableEdgeToEdgeCompat()

It's already in BaseActivity

Comment on lines +106 to +117
val selectedServerId: Int get() = viewState.selectedServerId
val selectedEntityId: String? get() = viewState.selectedEntityId
val appendAttributes: Boolean get() = viewState.appendAttributes
val selectedAttributeIds: List<String> get() = viewState.selectedAttributeIds
val label: String get() = viewState.label
val textSize: String get() = viewState.textSize
val stateSeparator: String get() = viewState.stateSeparator
val attributeSeparator: String get() = viewState.attributeSeparator
val selectedTapAction: WidgetTapAction get() = viewState.selectedTapAction
val selectedBackgroundType: WidgetBackgroundType get() = viewState.selectedBackgroundType
internal val selectedTextColor: EntityWidgetTextColor get() = viewState.selectedTextColor
val isUpdateWidget: Boolean get() = viewState.isUpdateWidget

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just expose the ViewState.

internal var widgetId: Int = AppWidgetManager.INVALID_APPWIDGET_ID
private set

val servers = serverManager.serversFlow

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this in the ViewState, and make it already a HADropdownItem so mapping happen in the viewModel scope. Same for the selected server it needs to be in the ViewState.


val servers = serverManager.serversFlow

internal var viewState by mutableStateOf(EntityWidgetConfigureViewState(selectedEntityId = preselectedEntityId))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use a mutableStateFlow

Comment on lines +53 to +63
internal data class EntityWidgetTextColors(val white: String, val black: String)

internal enum class EntityWidgetTextColor {
WHITE,
BLACK,
}

internal enum class EntityWidgetConfigureError {
CREATE,
UPDATE,
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something that is common to all the widget configure screen.

HADropdownItem(
key = WidgetTapAction.REFRESH,
label = stringResource(commonR.string.refresh),
),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remember the list to avoid recreating it on every recomposition

onTextColorSelected: (EntityWidgetTextColor) -> Unit,
) {
HADropdownMenu(
items = buildList {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here remember


if (selectedBackgroundType == WidgetBackgroundType.TRANSPARENT) {
HADropdownMenu(
items = listOf(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

onClick = onActionClick,
modifier = Modifier
.formControlWidth()
.testTag(ENTITY_WIDGET_ACTION_BUTTON_TAG),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use TAG when you can use the text

verticalArrangement = Arrangement.spacedBy(HADimens.SPACE2),
) {
unselectedAttributes.forEach { attributeId ->
InputChip(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's a M3 element it has the wrong colors, you need to use the HAColors (like you did for the the selected one ) so it gets the proper colors for light/dark and not the one from m3. The text needs to use a proper style too.

You could open a first PR that makes a HAInputChip for instance.

@home-assistant
home-assistant Bot marked this pull request as draft June 23, 2026 13:19
@home-assistant

Copy link
Copy Markdown

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@TimoPtr

TimoPtr commented Jun 23, 2026

Copy link
Copy Markdown
Member

Also I would like to see a close button in the topbar

Shaan-alpha added a commit to Shaan-alpha/android that referenced this pull request Jun 23, 2026
- Move media-player entity filtering and name resolution into the view
  model (uiState.availableEntities / selectedEntities) so the screen no
  longer filters or resolves names itself.
- Drop the wrapper Column in favour of a formControlWidth() modifier and
  extract EntityPickerSection, matching the entity widget (home-assistant#7007).
- Add a 'Selected entities:' title and a divider to the selection list.
- remember() the background-type option list.
- Replace the throwing check() in updateWidgetConfiguration() with a
  Boolean result that surfaces a user message; guard it in the activity.
- Share the entity/registry flows eagerly since the uiState combine keeps
  them subscribed for the view model's lifetime.
- Add a setScreen() test helper and a single combined interaction test
  covering the toggles, remove, action and close callbacks.
@TimoPtr TimoPtr linked an issue Jul 21, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate EnityWidgetConfigureActivity to compose and EntityPicker Rework UI of EntityWidgetConfigureActivity to compose and Material3

4 participants