Skip to content

Commit d795dcc

Browse files
authored
Migrate "Settings -> General" to SwiftUI (home-assistant#3558)
1 parent 32853f2 commit d795dcc

File tree

14 files changed

+474
-317
lines changed

14 files changed

+474
-317
lines changed

HomeAssistant.xcodeproj/project.pbxproj

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@
164164
1161C01B24D7634300A0E3C4 /* NFCListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1161C01A24D7634300A0E3C4 /* NFCListViewController.swift */; };
165165
1164D9DE25FB1B9800515E8A /* UIBarButtonItem+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164D9DD25FB1B9800515E8A /* UIBarButtonItem+Additions.swift */; };
166166
1164D9DF25FB1B9800515E8A /* UIBarButtonItem+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164D9DD25FB1B9800515E8A /* UIBarButtonItem+Additions.swift */; };
167-
1164DA2125FBEE8600515E8A /* TemplateEditViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164DA2025FBEE8600515E8A /* TemplateEditViewController.swift */; };
168167
1164DA3225FBF5D600515E8A /* UITextView+CodeRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1164DA3125FBF5D600515E8A /* UITextView+CodeRow.swift */; };
169168
11657050270188E4003906A7 /* URLComponents+WidgetAuthenticity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1165704F270188E4003906A7 /* URLComponents+WidgetAuthenticity.swift */; };
170169
11657051270188E4003906A7 /* URLComponents+WidgetAuthenticity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1165704F270188E4003906A7 /* URLComponents+WidgetAuthenticity.swift */; };
@@ -787,6 +786,8 @@
787786
429821142CD0DD85005ECD39 /* BluetoothPermissionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429821132CD0DD85005ECD39 /* BluetoothPermissionViewModel.swift */; };
788787
429821172CD0DDCD005ECD39 /* HAButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429821162CD0DDCD005ECD39 /* HAButtonStyles.swift */; };
789788
429821192CD0DEE2005ECD39 /* HAButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429821162CD0DDCD005ECD39 /* HAButtonStyles.swift */; };
789+
429AFE5C2DB7BE4000AF0836 /* GeneralSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429AFE5B2DB7BE4000AF0836 /* GeneralSettingsView.swift */; };
790+
429AFE5E2DB7DED300AF0836 /* GeneralSettingsTemplateEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429AFE5D2DB7DED300AF0836 /* GeneralSettingsTemplateEditor.swift */; };
790791
429BA2AF2C800CAB00A50996 /* SFSymbolEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429BA2AE2C800CAB00A50996 /* SFSymbolEntity.swift */; };
791792
429BEA1A2D102F3A00F070F9 /* ConnectionErrorDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429BEA192D102F3A00F070F9 /* ConnectionErrorDetailsView.swift */; };
792793
429BEA1D2D10315F00F070F9 /* SheetCloseButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429BEA1B2D1030EA00F070F9 /* SheetCloseButton.swift */; };
@@ -1682,7 +1683,6 @@
16821683
1164D9FE25FB417D00515E8A /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Intents.strings; sourceTree = "<group>"; };
16831684
1164DA0025FB41AE00515E8A /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/InfoPlist.strings; sourceTree = "<group>"; };
16841685
1164DA0125FB41AE00515E8A /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Localizable.strings; sourceTree = "<group>"; };
1685-
1164DA2025FBEE8600515E8A /* TemplateEditViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateEditViewController.swift; sourceTree = "<group>"; };
16861686
1164DA3125FBF5D600515E8A /* UITextView+CodeRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+CodeRow.swift"; sourceTree = "<group>"; };
16871687
1165704F270188E4003906A7 /* URLComponents+WidgetAuthenticity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLComponents+WidgetAuthenticity.swift"; sourceTree = "<group>"; };
16881688
1165705527018C4E003906A7 /* WidgetEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetEmptyView.swift; sourceTree = "<group>"; };
@@ -2216,6 +2216,8 @@
22162216
4297ADA62C89C74A00790812 /* GRDB+Initialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GRDB+Initialization.swift"; sourceTree = "<group>"; };
22172217
429821132CD0DD85005ECD39 /* BluetoothPermissionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothPermissionViewModel.swift; sourceTree = "<group>"; };
22182218
429821162CD0DDCD005ECD39 /* HAButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HAButtonStyles.swift; sourceTree = "<group>"; };
2219+
429AFE5B2DB7BE4000AF0836 /* GeneralSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsView.swift; sourceTree = "<group>"; };
2220+
429AFE5D2DB7DED300AF0836 /* GeneralSettingsTemplateEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsTemplateEditor.swift; sourceTree = "<group>"; };
22192221
429BA2AE2C800CAB00A50996 /* SFSymbolEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SFSymbolEntity.swift; sourceTree = "<group>"; };
22202222
429BEA192D102F3A00F070F9 /* ConnectionErrorDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionErrorDetailsView.swift; sourceTree = "<group>"; };
22212223
429BEA1B2D1030EA00F070F9 /* SheetCloseButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetCloseButton.swift; sourceTree = "<group>"; };
@@ -4481,6 +4483,15 @@
44814483
path = Styles;
44824484
sourceTree = "<group>";
44834485
};
4486+
429AFE5A2DB7BE3200AF0836 /* General */ = {
4487+
isa = PBXGroup;
4488+
children = (
4489+
429AFE5B2DB7BE4000AF0836 /* GeneralSettingsView.swift */,
4490+
429AFE5D2DB7DED300AF0836 /* GeneralSettingsTemplateEditor.swift */,
4491+
);
4492+
path = General;
4493+
sourceTree = "<group>";
4494+
};
44844495
42A2AB7E2C80750A00C5608D /* Control */ = {
44854496
isa = PBXGroup;
44864497
children = (
@@ -5239,6 +5250,7 @@
52395250
B661FB6B226BCC8500E541DD /* Settings */ = {
52405251
isa = PBXGroup;
52415252
children = (
5253+
429AFE5A2DB7BE3200AF0836 /* General */,
52425254
4211551F2D3525E800A71630 /* AppIcon */,
52435255
4278CB862D01F0BE00CFAAC9 /* Gestures */,
52445256
42EFFAEA2C8882CC002F10FC /* CarPlay */,
@@ -5258,7 +5270,6 @@
52585270
B641BC1D1E2097EF002CCBC1 /* AboutViewController.swift */,
52595271
B641BC221E209CA9002CCBC1 /* HomeAssistantLogoView.xib */,
52605272
1169B7AC25AA76E30035F2AE /* MaterialDesignIcons+Eureka.swift */,
5261-
1164DA2025FBEE8600515E8A /* TemplateEditViewController.swift */,
52625273
42B19BD02D4A358B00B3262B /* DebugView.swift */,
52635274
420C1BB32CF7DBF300AF22E7 /* ClientEventsLogView */,
52645275
119DE9552633A8C40099F7D8 /* SettingsRootDataSource.swift */,
@@ -7594,6 +7605,7 @@
75947605
425573C72B5572AD00145217 /* CarPlayServerListTemplate+Build.swift in Sources */,
75957606
B6DA3C7122690B1F00DE811C /* NotificationSoundsViewController.swift in Sources */,
75967607
424DD05A2B3509170057E456 /* CarPlayQuickAccessTemplate.swift in Sources */,
7608+
429AFE5E2DB7DED300AF0836 /* GeneralSettingsTemplateEditor.swift in Sources */,
75977609
42B94BDE2B9606CD00DEE060 /* AssistViewModel.swift in Sources */,
75987610
D0C88462211ED16300CCB501 /* OnboardingAuth.swift in Sources */,
75997611
11EFCDDC24F6065F00314D85 /* AboutSceneDelegate.swift in Sources */,
@@ -7628,6 +7640,7 @@
76287640
42C08CF72BA31F2700172EE5 /* CMSampleBuffer+AudioSamples.swift in Sources */,
76297641
42B1A7452C1305C300904548 /* WatchCommunicatorService.swift in Sources */,
76307642
42790C442C48077200E31B38 /* ImprovSuccessView.swift in Sources */,
7643+
429AFE5C2DB7BE4000AF0836 /* GeneralSettingsView.swift in Sources */,
76317644
425573ED2B58904000145217 /* CarPlayEntityListItem.swift in Sources */,
76327645
11F55ECD25D3A364003977AC /* NotificationRateLimitViewController.swift in Sources */,
76337646
3E4087F02CEC7F210085DF29 /* WidgetBasicSensorView.swift in Sources */,
@@ -7643,7 +7656,6 @@
76437656
42FCCFE32B9B1B610057783F /* BarcodeScannerCameraView.swift in Sources */,
76447657
11B62DBE24F2EDD800E5CB55 /* EurekaCondition+Additions.swift in Sources */,
76457658
4289DDAA2C85AB4C003591C2 /* AssistAppIntent.swift in Sources */,
7646-
1164DA2125FBEE8600515E8A /* TemplateEditViewController.swift in Sources */,
76477659
4273C4882C8857B00065A5B4 /* ControlOpenPage.swift in Sources */,
76487660
3E02C0E22CA7FCBF00102131 /* IntentSensorsAppEntity.swift in Sources */,
76497661
11A71C8B24A5848B00D9565F /* ZoneManagerProcessor.swift in Sources */,

Sources/App/Resources/en.lproj/Localizable.strings

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,10 +710,13 @@ Home Assistant is free and open source home automation software with a focus on
710710
"settings_details.general.pinch_to_zoom.title" = "Pinch to Zoom";
711711
"settings_details.general.restoration.title" = "Remember Last Page";
712712
"settings_details.general.title" = "General";
713+
"settings_details.general.body" = "Basic App configuration, App Icon and web page settings.";
713714
"settings_details.general.visibility.options.dock" = "Dock";
714715
"settings_details.general.visibility.options.dock_and_menu_bar" = "Dock and Menu Bar";
715716
"settings_details.general.visibility.options.menu_bar" = "Menu Bar";
716717
"settings_details.general.visibility.title" = "Show App In…";
718+
"settings_details.general.links.title" = "Links";
719+
"settings_details.general.page.title" = "Page";
717720
"settings_details.legacy_actions.title" = "(Legacy) iOS Actions";
718721
"settings_details.location.background_refresh.disabled" = "Disabled";
719722
"settings_details.location.background_refresh.enabled" = "Enabled";
@@ -1124,6 +1127,7 @@ Home Assistant is free and open source home automation software with a focus on
11241127
"watch.placeholder_complication_name" = "Placeholder";
11251128
"watch.settings.no_items.phone.title" = "No items configured, please choose items below.";
11261129
"web_view.server_selection.title" = "Choose server";
1130+
"web_view.unique_server_selection.title" = "Choose one server";
11271131
"widgets.action.name.assist" = "Assist";
11281132
"widgets.action.name.default" = "Default";
11291133
"widgets.action.name.navigate" = "Navigate";
@@ -1212,4 +1216,4 @@ Home Assistant is free and open source home automation software with a focus on
12121216
"widgets.sensors.description" = "Display state of sensors";
12131217
"widgets.sensors.not_configured" = "No Sensors Configured";
12141218
"widgets.sensors.title" = "Sensors";
1215-
"yes_label" = "Yes";
1219+
"yes_label" = "Yes";

Sources/App/Settings/DebugView.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ struct DebugView: View {
2727
var body: some View {
2828
List {
2929
AppleLikeListTopRowHeader(
30-
image: AnyView(Image(uiImage: MaterialDesignIcons.bugIcon.image(
31-
ofSize: .init(width: 120, height: 120),
32-
color: Asset.Colors.haPrimary.color
33-
))),
30+
image: .bugIcon,
3431
title: L10n.Settings.Debugging.Header.title,
3532
subtitle: L10n.Settings.Debugging.Header.subtitle
3633
)
@@ -132,6 +129,7 @@ struct DebugView: View {
132129
developerSection
133130
}
134131
}
132+
.removeListsPaddingWithAppleLikeHeader()
135133
}
136134

137135
private func linkContent(
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import HAKit
2+
import Shared
3+
import SwiftUI
4+
5+
struct GeneralSettingsTemplateEditor: View {
6+
@Environment(\.dismiss) private var dismiss
7+
@State private var template: String = Current.settingsStore.menuItemTemplate?.template ?? ""
8+
@State private var renderedTemplate: String = ""
9+
@State private var selectedServerId: String?
10+
@State private var isLoading = false
11+
@State private var currentTask: Task<Void, Never>?
12+
13+
private var selectedServer: Server? {
14+
guard let selectedServerId else { return nil }
15+
return Current.servers.all.first(where: { $0.identifier.rawValue == selectedServerId })
16+
}
17+
18+
var body: some View {
19+
List {
20+
Section(L10n.WebView.UniqueServerSelection.title) {
21+
ServersPickerPillList(selectedServerId: $selectedServerId)
22+
.padding(.vertical, Spaces.half)
23+
.listRowBackground(Color(uiColor: .systemBackground))
24+
}
25+
if selectedServerId != nil {
26+
Section(header: Text(L10n.SettingsDetails.General.MenuBarText.title)) {
27+
TextField("{{ now() }}", text: $template)
28+
}
29+
Section(L10n.previewOutput) {
30+
Text(renderedTemplate)
31+
}
32+
}
33+
}
34+
.navigationTitle(L10n.Settings.TemplateEdit.title)
35+
.toolbar {
36+
ToolbarItem(placement: .confirmationAction) {
37+
Button(L10n.saveLabel) {
38+
saveTemplate()
39+
}
40+
}
41+
}
42+
.onAppear {
43+
selectedServerId = Current.settingsStore.menuItemTemplate?.server.identifier.rawValue ?? nil
44+
renderTemplate()
45+
}
46+
.onChange(of: template) { newValue in
47+
renderTemplate(newValue)
48+
}
49+
}
50+
51+
private func saveTemplate() {
52+
guard let server = selectedServer else { return }
53+
Current.settingsStore.menuItemTemplate = (server, template)
54+
dismiss()
55+
}
56+
57+
private func renderTemplate(_ template: String? = nil) {
58+
let template = template ?? self.template
59+
guard let server = selectedServer, let api = Current.api(for: server) else { return }
60+
isLoading = true
61+
currentTask?.cancel()
62+
currentTask = Task {
63+
let result = await withCheckedContinuation { continuation in
64+
api.connection.send(.init(
65+
type: .rest(.post, "template"),
66+
data: ["template": template],
67+
shouldRetry: true
68+
)) { result in
69+
continuation.resume(returning: result)
70+
}
71+
}
72+
73+
var data: HAData?
74+
switch result {
75+
case let .success(resultData):
76+
data = resultData
77+
case let .failure(error):
78+
Current.Log.error("Error rendering template: \(error)")
79+
renderedTemplate = error.localizedDescription
80+
}
81+
guard let data else {
82+
Current.Log.error("No data returned from template rendering")
83+
renderedTemplate = "-"
84+
return
85+
}
86+
switch data {
87+
case let .primitive(response):
88+
renderedTemplate = response as? String ?? "-"
89+
default:
90+
Current.Log.error("Unexpected data type returned from template rendering")
91+
renderedTemplate = "-"
92+
}
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)