iOS/Sources/App/WebView/ExperimentalSpace/AppIntentProvider.swift
Copilot 8cdfb4f294
Experiment: Native HomeView/dashboard (#4142)
Basic implementation of a native dashboard - WIP

- [ ] Support more domains toggle action when tapping icon
  - [x] Light
  - [x] Cover
  - [x] Switch
- [ ] Create the equivalent of "more info dialog" for each domain
  - [x] Light
  - [x] Cover
  - [x] Switch
- [x] Add haptics
- [ ] Add more cards such as a camera card
- [ ] Find a way to display sensors information such as humidity and
temperature
- [ ] Allow customizing background
- [x] Allow opening the native dashboard from iOS controls
- [ ] Allow opening the native dashboard from Shortcuts
- [ ] Add an advanced option somewhere in settings that allow user to
see the native dashboard first instead of web UI
- [ ] Add error state
- [x] Add empty state
- [x] Add loading state
- [x] Allow reordering rooms
- [x] Allow reordering cards

<img width="1232" height="1158" alt="CleanShot 2026-01-05 at 16 19
59@2x"
src="https://github.com/user-attachments/assets/84ae8748-ec40-430c-a820-fcb6a88a6270"
/>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com>
2026-01-05 22:38:09 +00:00

91 lines
3.4 KiB
Swift

import AppIntents
import Foundation
import HAKit
import Shared
@available(iOS 18.0, *)
/// A service that provides the appropriate AppIntent for a given HAEntity
enum AppIntentProvider {
/// Returns an AppIntent configured for the given entity and server
/// - Parameters:
/// - haEntity: The HAEntity to create an intent for
/// - server: The server the entity belongs to
/// - Returns: An AppIntent configured for the entity's domain
static func intent(for haEntity: HAEntity, server: Server) -> any AppIntent {
let domain = Domain(entityId: haEntity.entityId)
switch domain {
case .light:
return lightIntent(for: haEntity, server: server)
case .cover:
return coverIntent(for: haEntity, server: server)
case .switch, .inputBoolean:
return switchIntent(for: haEntity, server: server)
case .fan:
return fanIntent(for: haEntity, server: server)
default:
// Default fallback - returns a switch intent as a safe default
// since it handles multiple domains including input_boolean
return switchIntent(for: haEntity, server: server)
}
}
// MARK: - Private Intent Builders
private static func lightIntent(for haEntity: HAEntity, server: Server) -> LightIntent {
let intent = LightIntent()
intent.light = .init(
id: haEntity.entityId,
entityId: haEntity.entityId,
serverId: server.identifier.rawValue,
displayString: haEntity.attributes.friendlyName ?? haEntity.entityId,
iconName: haEntity.attributes.icon ?? ""
)
intent.toggle = true
intent.value = false // Default value when toggle is true
return intent
}
private static func coverIntent(for haEntity: HAEntity, server: Server) -> CoverIntent {
let intent = CoverIntent()
intent.entity = .init(
id: haEntity.entityId,
entityId: haEntity.entityId,
serverId: server.identifier.rawValue,
displayString: haEntity.attributes.friendlyName ?? haEntity.entityId,
iconName: haEntity.attributes.icon ?? ""
)
intent.toggle = true
intent.value = false // Default value when toggle is true
return intent
}
private static func switchIntent(for haEntity: HAEntity, server: Server) -> SwitchIntent {
let intent = SwitchIntent()
intent.entity = .init(
id: haEntity.entityId,
entityId: haEntity.entityId,
serverId: server.identifier.rawValue,
displayString: haEntity.attributes.friendlyName ?? haEntity.entityId,
iconName: haEntity.attributes.icon ?? ""
)
intent.toggle = true
intent.value = false // Default value when toggle is true
return intent
}
private static func fanIntent(for haEntity: HAEntity, server: Server) -> FanIntent {
let intent = FanIntent()
intent.fan = .init(
id: haEntity.entityId,
entityId: haEntity.entityId,
serverId: server.identifier.rawValue,
displayString: haEntity.attributes.friendlyName ?? haEntity.entityId,
iconName: haEntity.attributes.icon ?? ""
)
intent.toggle = true
intent.value = false // Default value when toggle is true
return intent
}
}