Skip to content

Commit

Permalink
Add introduction to iOS actions coming from CarPlay (#2528)
Browse files Browse the repository at this point in the history
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->
<img width="1724" alt="Screenshot 2024-01-18 at 01 26 26"
src="https://github.com/home-assistant/iOS/assets/5808343/2ef9e945-c7c1-4659-85e9-5dab9f2a791d">

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->
  • Loading branch information
bgoncal committed Jan 18, 2024
1 parent ca0313d commit 0383068
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 64 deletions.
8 changes: 8 additions & 0 deletions HomeAssistant.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@
425573E72B5838BB00145217 /* HATypedRequest+CarPlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F1DA572B46FDD8002729BC /* HATypedRequest+CarPlay.swift */; };
425573E82B5838E300145217 /* HAAreaResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F1DA6F2B4EE2E8002729BC /* HAAreaResponse.swift */; };
425573E92B58396600145217 /* HAEntity+CarPlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3BC66629BA003B00B19FBE /* HAEntity+CarPlay.swift */; };
425573EB2B588FFB00145217 /* CarPlayListItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425573EA2B588FFB00145217 /* CarPlayListItemProvider.swift */; };
425573ED2B58904000145217 /* CarPlayEntityListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425573EC2B58904000145217 /* CarPlayEntityListItem.swift */; };
425573EF2B589B0F00145217 /* NotificationIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425573EE2B589B0F00145217 /* NotificationIdentifier.swift */; };
426740A92B17391000C1DD73 /* Data+Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 426740A72B17390A00C1DD73 /* Data+Hexadecimal.swift */; };
4278DFD22B45C7AE0087C9D7 /* Core.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4278DFAF2B45C6680087C9D7 /* Core.strings */; };
4278DFD32B45C7AE0087C9D7 /* Core.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4278DFAF2B45C6680087C9D7 /* Core.strings */; };
Expand Down Expand Up @@ -1607,6 +1610,9 @@
425573D02B5576E600145217 /* CarPlayDomainsListTemplate+Build.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CarPlayDomainsListTemplate+Build.swift"; sourceTree = "<group>"; };
425573D22B55770D00145217 /* CarPlayDomainsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarPlayDomainsListViewModel.swift; sourceTree = "<group>"; };
425573E42B58380D00145217 /* CarPlay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CarPlay.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/System/iOSSupport/System/Library/Frameworks/CarPlay.framework; sourceTree = DEVELOPER_DIR; };
425573EA2B588FFB00145217 /* CarPlayListItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarPlayListItemProvider.swift; sourceTree = "<group>"; };
425573EC2B58904000145217 /* CarPlayEntityListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarPlayEntityListItem.swift; sourceTree = "<group>"; };
425573EE2B589B0F00145217 /* NotificationIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationIdentifier.swift; sourceTree = "<group>"; };
426740A72B17390A00C1DD73 /* Data+Hexadecimal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Hexadecimal.swift"; sourceTree = "<group>"; };
4278DFB02B45C6680087C9D7 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Core.strings; sourceTree = "<group>"; };
4278DFB12B45C6680087C9D7 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Core.strings"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2532,6 +2538,7 @@
11195F6E267EFC8E003DF674 /* NotificationManagerLocalPushInterfaceDirect.swift */,
11B92A7F266F23CD00786588 /* NotificationManagerLocalPushInterfaceExtension.swift */,
11195F70267EFE2C003DF674 /* NotificationManagerLocalPushInterfaceUnsupported.swift */,
425573EE2B589B0F00145217 /* NotificationIdentifier.swift */,
);
path = Notifications;
sourceTree = "<group>";
Expand Down Expand Up @@ -5674,6 +5681,7 @@
B675ECC3221BB0E600C65D31 /* SearchPushRow.swift in Sources */,
11C05F2D254919210031D038 /* AccountInitialsImage.swift in Sources */,
B605C891226E9DAC00EF46DD /* Permissions.swift in Sources */,
425573EF2B589B0F00145217 /* NotificationIdentifier.swift in Sources */,
425573D32B55770D00145217 /* CarPlayDomainsListViewModel.swift in Sources */,
1169B7AD25AA76E30035F2AE /* MaterialDesignIcons+Eureka.swift in Sources */,
425573E82B5838E300145217 /* HAAreaResponse.swift in Sources */,
Expand Down
5 changes: 5 additions & 0 deletions Sources/App/Notifications/NotificationIdentifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Foundation

enum NotificationIdentifier: String {
case carPlayActionIntro = "CarPlay-action-intro"
}
16 changes: 16 additions & 0 deletions Sources/App/Notifications/NotificationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,22 @@ extension NotificationManager: UNUserNotificationCenterDelegate {
} else {
completionHandler()
}

if response.notification.request.identifier == NotificationIdentifier.carPlayActionIntro.rawValue {
Current.Log.info("launching iOS Actions configuration screen")
Current.sceneManager.webViewWindowControllerPromise.done {
let settingsView = SettingsDetailViewController()
settingsView.detailGroup = .actions
let navController = UINavigationController(rootViewController: settingsView)
settingsView.navigationItem.rightBarButtonItem = UIBarButtonItem(
systemItem: .close,
primaryAction: .init(handler: { _ in
navController.dismiss(animated: true)
})
)
$0.present(navController)
}
}
}

public func userNotificationCenter(
Expand Down
26 changes: 16 additions & 10 deletions Sources/App/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,18 @@
"carPlay.no_actions.title" = "Open iOS Companion App to create actions for CarPlay.";
"carPlay.no_entities.title" = "No CarPlay compatible entities available.";
"carPlay.unlock.confirmation.title" = "Are you sure you want to perform unlock action on %@?";
"carplay.labels.already_added_server" = "Already added";
"carplay.labels.empty_domain_list" = "No domains available";
"carplay.labels.no_servers_available" = "No servers available. Add a server in the app.";
"carplay.labels.servers" = "Servers";
"carplay.lock.confirmation.title" = "Are you sure you want to perform lock action on %@?";
"carplay.navigation.button.next" = "Next";
"carplay.navigation.button.previous" = "Previous";
"carplay.unlock.confirmation.title" = "Are you sure you want to perform unlock action on %@?";
"carPlay.labels.already_added_server" = "Already added";
"carPlay.labels.empty_domain_list" = "No domains available";
"carPlay.labels.no_servers_available" = "No servers available. Add a server in the app.";
"carPlay.labels.servers" = "Servers";
"carPlay.lock.confirmation.title" = "Are you sure you want to perform lock action on %@?";
"carPlay.navigation.button.next" = "Next";
"carPlay.navigation.button.previous" = "Previous";
"carPlay.unlock.confirmation.title" = "Are you sure you want to perform unlock action on %@?";
"carPlay.notification.action.intro.title" = "Create iOS Action";
"carPlay.notification.action.intro.body" = "Tap to create your first iOS Action";
"carPlay.action.intro.item.title" = "Create your first action";
"carPlay.action.intro.item.body" = "Tap to continue on your iPhone";
"cl_error.description.deferred_accuracy_too_low" = "Deferred mode is not supported for the requested accuracy.";
"cl_error.description.deferred_canceled" = "The request for deferred updates was canceled by your app or by the location manager.";
"cl_error.description.deferred_distance_filtered" = "Deferred mode does not support distance filters.";
Expand Down Expand Up @@ -385,7 +389,8 @@ Home Assistant is free and open source home automation software with a focus on
"settings_details.actions.actions_synced.footer" = "Actions defined in .yaml are not editable on device.";
"settings_details.actions.actions_synced.footer_no_actions" = "Actions may be also defined in the .yaml configuration.";
"settings_details.actions.actions_synced.header" = "Synced Actions";
"settings_details.actions.footer" = "Actions are used in the Apple Watch app, App Icon Actions and the Today widget";
"settings_details.actions.footer" = "Actions are used in the Apple Watch app, App Icon Actions, the Today widget and CarPlay.";
"settings_details.actions.learn.button.title" = "Introduction to iOS Actions";
"settings_details.actions.footer_mac" = "Actions are used in the application menu and widgets.";
"settings_details.actions.scenes.customize_action" = "Customize";
"settings_details.actions.scenes.empty" = "No Scenes";
Expand Down Expand Up @@ -808,4 +813,5 @@ Home Assistant is free and open source home automation software with a focus on
"widgets.open_page.description" = "Open a frontend page in Home Assistant.";
"widgets.open_page.not_configured" = "No Pages Available";
"widgets.open_page.title" = "Open Page";
"yes_label" = "Yes";
"yes_label" = "Yes";
"navBar.close" = "Close";
2 changes: 1 addition & 1 deletion Sources/App/Scenes/SettingsSceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ import UIKit
} else {
navigationController?.pushViewController(
with(SettingsDetailViewController()) {
$0.detailGroup = "actions"
$0.detailGroup = .actions
},
animated: animated
)
Expand Down
31 changes: 26 additions & 5 deletions Sources/App/Settings/SettingsDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ import Shared
import UIKit
import Version

enum SettingsDetailsGroup: String {
case display
case actions
case general
case location
case privacy
}

class SettingsDetailViewController: HAFormViewController, TypedRowControllerType {
var row: RowOf<ButtonRow>!
/// A closure to be called when the controller disappears.
public var onDismissCallback: ((UIViewController) -> Void)?

var detailGroup: String = "display"
var detailGroup: SettingsDetailsGroup = .display

var doneButton: Bool = false

Expand Down Expand Up @@ -52,7 +60,7 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
}

switch detailGroup {
case "general":
case .general:
title = L10n.SettingsDetails.General.title

form
Expand Down Expand Up @@ -264,7 +272,7 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
}
}

case "location":
case .location:
title = L10n.SettingsDetails.Location.title
form
+++ locationPermissionsSection()
Expand Down Expand Up @@ -388,7 +396,7 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
}
}

case "actions":
case .actions:
title = L10n.SettingsDetails.Actions.title
let actions = realm.objects(Action.self)
.sorted(byKeyPath: "Position")
Expand All @@ -397,6 +405,19 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
let actionsFooter = Current.isCatalyst ?
L10n.SettingsDetails.Actions.footerMac : L10n.SettingsDetails.Actions.footer

let learnAboutActionsButton = ButtonRow {
$0.title = L10n.SettingsDetails.Actions.Learn.Button.title
$0.tag = "actions_learn_more"
$0.cellStyle = .value1
$0.cellUpdate { cell, _ in
cell.accessoryType = .detailButton
}
$0.onCellSelection { _, _ in
guard let url = URL(string: "https://companion.home-assistant.io/docs/core/actions/") else { return }
UIApplication.shared.open(url)
}
}
form +++ learnAboutActionsButton
form +++ MultivaluedSection(
multivaluedOptions: [.Insert, .Delete, .Reorder],
header: "",
Expand Down Expand Up @@ -483,7 +504,7 @@ class SettingsDetailViewController: HAFormViewController, TypedRowControllerType
}
)

case "privacy":
case .privacy:
title = L10n.SettingsDetails.Privacy.title

form
Expand Down
8 changes: 4 additions & 4 deletions Sources/App/Settings/SettingsRootDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ enum SettingsRootDataSource {
$0.icon = .paletteOutlineIcon
$0.presentationMode = .show(controllerProvider: ControllerProvider.callback {
let view = SettingsDetailViewController()
view.detailGroup = "general"
view.detailGroup = .general
return view
}, onDismiss: nil)
}
Expand All @@ -81,7 +81,7 @@ enum SettingsRootDataSource {
$0.icon = .crosshairsGpsIcon
$0.presentationMode = .show(controllerProvider: ControllerProvider.callback {
let view = SettingsDetailViewController()
view.detailGroup = "location"
view.detailGroup = .location
return view
}, onDismiss: nil)
}
Expand All @@ -103,7 +103,7 @@ enum SettingsRootDataSource {
$0.icon = .gamepadVariantOutlineIcon
$0.presentationMode = .show(controllerProvider: ControllerProvider.callback {
let view = SettingsDetailViewController()
view.detailGroup = "actions"
view.detailGroup = .actions
return view
}, onDismiss: nil)
}
Expand Down Expand Up @@ -162,7 +162,7 @@ enum SettingsRootDataSource {
$0.icon = .lockOutlineIcon
$0.presentationMode = .show(controllerProvider: .callback {
let view = SettingsDetailViewController()
view.detailGroup = "privacy"
view.detailGroup = .privacy
return view
}, onDismiss: nil)
}
Expand Down
66 changes: 30 additions & 36 deletions Sources/Shared/Resources/Swiftgen/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ public enum L10n {
}

public enum CarPlay {
public enum Action {
public enum Intro {
public enum Item {
/// Continue on your iPhone
public static var body: String { return L10n.tr("Localizable", "carPlay.action.intro.item.body") }
/// Create your first action
public static var title: String { return L10n.tr("Localizable", "carPlay.action.intro.item.title") }
}
}
}
public enum Labels {
/// Already added
public static var alreadyAddedServer: String { return L10n.tr("Localizable", "carPlay.labels.already_added_server") }
Expand Down Expand Up @@ -278,48 +288,21 @@ public enum L10n {
/// No CarPlay compatible entities available.
public static var title: String { return L10n.tr("Localizable", "carPlay.no_entities.title") }
}
public enum Unlock {
public enum Confirmation {
/// Are you sure you want to perform unlock action on %@?
public static func title(_ p1: Any) -> String {
return L10n.tr("Localizable", "carPlay.unlock.confirmation.title", String(describing: p1))
}
}
}
}

public enum Carplay {
public enum Labels {
/// Already added
public static var alreadyAddedServer: String { return L10n.tr("Localizable", "carplay.labels.already_added_server") }
/// No domains available
public static var emptyDomainList: String { return L10n.tr("Localizable", "carplay.labels.empty_domain_list") }
/// No servers available. Add a server in the app.
public static var noServersAvailable: String { return L10n.tr("Localizable", "carplay.labels.no_servers_available") }
/// Servers
public static var servers: String { return L10n.tr("Localizable", "carplay.labels.servers") }
}
public enum Lock {
public enum Confirmation {
/// Are you sure you want to perform lock action on %@?
public static func title(_ p1: Any) -> String {
return L10n.tr("Localizable", "carplay.lock.confirmation.title", String(describing: p1))
public enum Notification {
public enum Action {
public enum Intro {
/// Tap to create your first iOS Action
public static var body: String { return L10n.tr("Localizable", "carPlay.notification.action.intro.body") }
/// Create iOS Action
public static var title: String { return L10n.tr("Localizable", "carPlay.notification.action.intro.title") }
}
}
}
public enum Navigation {
public enum Button {
/// Next
public static var next: String { return L10n.tr("Localizable", "carplay.navigation.button.next") }
/// Previous
public static var previous: String { return L10n.tr("Localizable", "carplay.navigation.button.previous") }
}
}
public enum Unlock {
public enum Confirmation {
/// Are you sure you want to perform unlock action on %@?
public static func title(_ p1: Any) -> String {
return L10n.tr("Localizable", "carplay.unlock.confirmation.title", String(describing: p1))
return L10n.tr("Localizable", "carPlay.unlock.confirmation.title", String(describing: p1))
}
}
}
Expand Down Expand Up @@ -611,6 +594,11 @@ public enum L10n {
}
}

public enum NavBar {
/// Close
public static var close: String { return L10n.tr("Localizable", "navBar.close") }
}

public enum Nfc {
/// Tag Read
public static var genericTagRead: String { return L10n.tr("Localizable", "nfc.generic_tag_read") }
Expand Down Expand Up @@ -1321,7 +1309,7 @@ public enum L10n {

public enum SettingsDetails {
public enum Actions {
/// Actions are used in the Apple Watch app, App Icon Actions and the Today widget
/// Actions are used in the Apple Watch app, App Icon Actions, the Today widget and CarPlay.
public static var footer: String { return L10n.tr("Localizable", "settings_details.actions.footer") }
/// Actions are used in the application menu and widgets.
public static var footerMac: String { return L10n.tr("Localizable", "settings_details.actions.footer_mac") }
Expand All @@ -1337,6 +1325,12 @@ public enum L10n {
/// Synced Actions
public static var header: String { return L10n.tr("Localizable", "settings_details.actions.actions_synced.header") }
}
public enum Learn {
public enum Button {
/// Introduction to iOS Actions
public static var title: String { return L10n.tr("Localizable", "settings_details.actions.learn.button.title") }
}
}
public enum Scenes {
/// Customize
public static var customizeAction: String { return L10n.tr("Localizable", "settings_details.actions.scenes.customize_action") }
Expand Down

0 comments on commit 0383068

Please sign in to comment.