iOS/Sources/Shared/API/Models/NotificationAction.swift
Zac West 5c104f76e9
Multi-server (#1906)
## Summary
Most, but not all, of the changes necessary to support multi-server throughout the app and all its features.

## Screenshots
| Light | Dark |
| ----- | ---- |
| ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 52 24](https://user-images.githubusercontent.com/74188/143670011-9b9905ac-1b5b-4a82-b9f3-1490465c4ec5.png) | ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 52 26](https://user-images.githubusercontent.com/74188/143670012-0080230a-8f68-4f34-9691-db9f5e825a83.png) |
| ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 52 30](https://user-images.githubusercontent.com/74188/143670015-ceeac558-e039-4639-a186-b5001ab418b8.png) | ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 52 29](https://user-images.githubusercontent.com/74188/143670016-d72bb69d-83f5-4197-a742-59d208467258.png) |
| ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 52 47](https://user-images.githubusercontent.com/74188/143670021-6c90c40f-c2f1-4a33-aad9-da6626e99d9d.png) | ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 52 45](https://user-images.githubusercontent.com/74188/143670024-e99de69d-61d8-4e12-be73-a172242806a0.png) |
| ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 53 05](https://user-images.githubusercontent.com/74188/143670033-1a41ac7e-d4d1-458b-974e-2efdaf8e2288.png) | ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 53 03](https://user-images.githubusercontent.com/74188/143670049-baf4db64-64db-4bfb-88cf-4930f9e5661b.png) |
| ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 53 21](https://user-images.githubusercontent.com/74188/143670053-7ec794f1-857c-4ef6-a92a-5318e90ac6b6.png) | ![Simulator Screen Shot - iPhone 13 Pro - 2021-11-26 at 21 53 19](https://user-images.githubusercontent.com/74188/143670056-a6a5207c-3bba-49fc-b5c6-fc6fa8141f9c.png) |

## Any other notes
- Encapsulates all connectivity, token & server-specific knowledge in a Server model object which gets passed around.
- Updates various places throughout the app to know about and use Server rather than accessing said information through non-server-specific methods.
- Visually requests/notes server in places where it's ambiguous. For example, the Open Page widget will gain a subtitle if multiple servers are set up.
- Allows switching which server is shown in the WebViews. Note that this doesn't take into account multi-window support on iPad/macOS yet.

Most things will migrate successfully however adding an additional server causes things like Shortcuts to start erroring requiring you specify which to use in the particular Shortcut.

Future work necessary:
- Model objects currently clobber each other if their identifiers match. For example, both servers having a zone named `home` means one of them wins the fight for which is known to the app.
- Being remotely logged out on any account causes the app to require onboarding again, when instead it should only do that if the last known server is logged out.
2021-11-27 12:33:46 -08:00

141 lines
4.9 KiB
Swift

import Foundation
import RealmSwift
import UserNotifications
public class NotificationAction: Object {
@objc public dynamic var uuid: String = UUID().uuidString
@objc public dynamic var Identifier: String = ""
@objc public dynamic var Title: String = ""
@objc public dynamic var TextInput: Bool = false
@objc public dynamic var isServerControlled: Bool = false
@objc public dynamic var icon: String?
// Options
@objc public dynamic var Foreground: Bool = false
@objc public dynamic var Destructive: Bool = false
@objc public dynamic var AuthenticationRequired: Bool = false
// Text Input Options
@objc public dynamic var TextInputButtonTitle: String = L10n.NotificationsConfigurator.Action.Rows
.TextInputButtonTitle.title
@objc public dynamic var TextInputPlaceholder: String = L10n.NotificationsConfigurator.Action.Rows
.TextInputPlaceholder.title
// swiftlint:enable line_length
public convenience init(action: MobileAppConfigPushCategory.Action) {
self.init()
self.isServerControlled = true
self.Title = action.title
self.Identifier = action.identifier
self.AuthenticationRequired = action.authenticationRequired
self.Foreground = (action.activationMode.lowercased() == "foreground")
self.Destructive = action.destructive
self.TextInput = (action.behavior.lowercased() == "textinput")
self.icon = action.icon
if let title = action.textInputButtonTitle {
self.TextInputButtonTitle = title
} else {
self.TextInputButtonTitle = L10n.NotificationsConfigurator.Action.Rows.TextInputButtonTitle.title
}
if let placeholder = action.textInputPlaceholder {
self.TextInputPlaceholder = placeholder
} else {
self.TextInputPlaceholder = L10n.NotificationsConfigurator.Action.Rows.TextInputPlaceholder.title
}
}
override public static func primaryKey() -> String? {
"uuid"
}
public let categories = LinkingObjects(fromType: NotificationCategory.self, property: "Actions")
public var options: UNNotificationActionOptions {
var actionOptions = UNNotificationActionOptions([])
if AuthenticationRequired { actionOptions.insert(.authenticationRequired) }
if Destructive { actionOptions.insert(.destructive) }
if Foreground { actionOptions.insert(.foreground) }
return actionOptions
}
public var action: UNNotificationAction {
let action: UNNotificationAction
let baseAction: () -> UNNotificationAction = { [self] in
if TextInput {
return UNTextInputNotificationAction(
identifier: Identifier,
title: Title,
options: options,
textInputButtonTitle: TextInputButtonTitle,
textInputPlaceholder: TextInputPlaceholder
)
} else {
return UNNotificationAction(
identifier: Identifier,
title: Title,
options: options
)
}
}
if #available(iOS 15, watchOS 8, *) {
let actionIcon: UNNotificationActionIcon?
if let icon = icon, icon.hasPrefix("sfsymbols:") {
actionIcon = .init(systemImageName: icon.replacingOccurrences(of: "sfsymbols:", with: ""))
} else {
actionIcon = nil
}
if TextInput {
action = UNTextInputNotificationAction(
identifier: Identifier,
title: Title,
options: options,
icon: actionIcon,
textInputButtonTitle: TextInputButtonTitle,
textInputPlaceholder: TextInputPlaceholder
)
} else {
action = UNNotificationAction(
identifier: Identifier,
title: Title,
options: options,
icon: actionIcon
)
}
} else {
action = baseAction()
}
return action
}
public class func exampleTrigger(
api: HomeAssistantAPI,
identifier: String,
category: String?,
textInput: Bool
) -> String {
let data = api.legacyNotificationActionEvent(
identifier: identifier,
category: category,
actionData: "# value of action_data in notify call",
textInput: textInput ? "# text you input" : nil
)
let eventDataStrings = data.eventData.map { $0 + ": " + String(describing: $1) }.sorted()
let indentation = "\n "
return """
- platform: event
event_type: \(data.eventType)
event_data:
\(eventDataStrings.joined(separator: indentation))
"""
}
}