diff --git a/Images/Rebranding/rebranding-6.png b/Images/Rebranding/rebranding-6.png
index 0b4fd52..335786a 100644
Binary files a/Images/Rebranding/rebranding-6.png and b/Images/Rebranding/rebranding-6.png differ
diff --git a/Images/SystemAlert/systemalert.png b/Images/SystemAlert/systemalert.png
new file mode 100644
index 0000000..22c87c2
Binary files /dev/null and b/Images/SystemAlert/systemalert.png differ
diff --git a/Notification Agent Alerts/AppDelegate.swift b/Notification Agent Alerts/AppDelegate.swift
index f677eef..96b30e0 100644
--- a/Notification Agent Alerts/AppDelegate.swift
+++ b/Notification Agent Alerts/AppDelegate.swift
@@ -25,7 +25,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return
}
isConfigured = true
- NSApplication.shared.activate(ignoringOtherApps: true)
notificationDispatch.startObservingForNotifications()
guard !UserNotificationController.shared.agentTriggeredByNotificationCenter else {
completion()
diff --git a/Notification Agent Alerts/Info.plist b/Notification Agent Alerts/Info.plist
index 687d4e5..6a11bc8 100644
--- a/Notification Agent Alerts/Info.plist
+++ b/Notification Agent Alerts/Info.plist
@@ -17,7 +17,7 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
+ 96
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/Notification Agent Banners/AppDelegate.swift b/Notification Agent Banners/AppDelegate.swift
index 7cb3eac..902807d 100644
--- a/Notification Agent Banners/AppDelegate.swift
+++ b/Notification Agent Banners/AppDelegate.swift
@@ -24,7 +24,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return
}
isConfigured = true
- NSApplication.shared.activate(ignoringOtherApps: true)
notificationDispatch.startObservingForNotifications()
guard !UserNotificationController.shared.agentTriggeredByNotificationCenter else {
completion()
diff --git a/Notification Agent Banners/Info.plist b/Notification Agent Banners/Info.plist
index 3ea67e1..a76d44f 100644
--- a/Notification Agent Banners/Info.plist
+++ b/Notification Agent Banners/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
+ 96
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/Notification Agent Core/Controllers/HelpBuilder.swift b/Notification Agent Core/Controllers/HelpBuilder.swift
index 4c960de..143c9ef 100644
--- a/Notification Agent Core/Controllers/HelpBuilder.swift
+++ b/Notification Agent Core/Controllers/HelpBuilder.swift
@@ -6,7 +6,7 @@
// Copyright © 2021 IBM Inc. All rights reserved
// SPDX-License-Identifier: Apache2.0
//
-// swiftlint:disable type_body_length
+// swiftlint:disable type_body_length file_length
import Foundation
public final class HelpBuilder {
@@ -61,6 +61,21 @@ public final class HelpBuilder {
"-payload".green(),
"-always_on_top".yellow(),
"-hide_title_bar_buttons".yellow()]
+ static let systemAlertArguments: [String] = ["-type".green(),
+ "-title".yellow(),
+ "-subtitle".yellow(),
+ "-icon_path".yellow(),
+ "-main_button_label".yellow(),
+ "-main_button_cta_type".yellow(),
+ "-main_button_cta_payload".yellow(),
+ "-secondary_button_label".yellow(),
+ "-secondary_button_cta_type".yellow(),
+ "-secondary_button_cta_payload".yellow(),
+ "-tertiary_button_label".yellow(),
+ "-tertiary_button_cta_type".yellow(),
+ "-tertiary_button_cta_payload".yellow(),
+ "-silent".yellow(),
+ "-showSuppressionButton".yellow()]
static let popupDescriptions: [String] = ["[ popup ]".red() + "\n The UI type of the notification.\n Example: -type popup",
"\n The bar title.\n Example: -bar_title \"Bar Title\"",
"\n The title of the notification.\n Suggested length < 120 characters.\n Allowed length < 240 characters.\n Example: -title \"Title\"",
@@ -125,12 +140,29 @@ public final class HelpBuilder {
"\n The json payload for the \"onboarding\" UI type.\n Example: -payload \"{ \"pages\": [\n {\n \"title\": \"Some title\",\n \"subtitle\": \"Some subtitle\",\n \"body\": \"Some body\",\n \"accessoryViews\": \"[\n [\n {\n \"type\": \"input\"\n \"payload\": \"/placeholder Something /title First\"\n },\n {\n \"type\": \"input\"\n \"payload\": \"/placeholder Something /title Second\"\n }\n ],\n [\n {\n \"type\": \"image\"\n \"payload\": \"/local/or/remote/path/to/image.png\"\n },\n {\n \"type\": \"video\"\n \"payload\": \"/local/or/remote/path/to/video.mov\"\n }\n ]\n ]\n }\n ]\n }\"\n Please see more about this feature on the project wiki.",
"\n Flag that tells the agent to keep the Onbording UI always on top of the window hierarchy.\n Example: -always_on_top",
"\n Flag that tells the agent to remove the title bar buttons for the Onbording UI.\n Example: -hide_title_bar_buttons"]
+ static let systemAlertDescriptions: [String] = ["[ systemAlert ]".red() + "\n The UI type of the notification.\n Example: -type popup",
+ "\n The title of the notification.\n Example: -title \"Title\"",
+ "\n The subtitle of the notification.\n Example: -subtitle \"Subtitle\"",
+ "\n The custom icon path defined for this notification.\n Example: -icon_path \"~/Icon/Path.png\"",
+ "\n The label of the main button.\n Example: -main_button_label \"Main button title\"",
+ "[ none | link ]".red() + "\n The call to action type for the main button (default: none -> exit).\n Example: -main_button_cta_type link",
+ "\n An URL if " + "[ link ]".red() + " cta type defined.\n Example: -main_button_cta_payload \"URL\"",
+ "\n The label of the secondary button.\n Example: -secondary_button_label \"Secondary button title\"",
+ "[ none | link ]".red() + "\n The call to action type for the secondary button (default: none -> exit).\n Example: -secondary_button_cta_type link",
+ "\n An URL if " + "[ link ]".red() + " cta type defined.\n Example: -secondary_button_cta_payload \"URL\"",
+ "\n The label of the tertiary button.\n Example: -tertiary_button_label \"Tertiary button title\"",
+ "[ link | exitlink ]".red() + "\n The call to action type for the tertiary button.\n Example: -tertiary_button_cta_type link",
+ "\n A mandatory URL if " + "[ link ]".red() + " cta type defined, optional if " + "[ exitlink ]".red() + " cta defined.\n Example: -tertiary_button_cta_payload \"URL\"",
+ "\n Flag that tells the agent to not reproduce any sound when the pop-up appear.\n Example: -silent",
+ "\n Flag that tells the agent to show the suppression future notifications button on the UI. If checked by the user the agent will print \"suppressed\" in the output before exit.\n Example: -showSuppressionButton"]
static let popupSyntacticRules: [String] = ["At least one argument between" + " [ -title | -subtitle | -accessory_view_type + -accessory_view_payload ] ".red() + "must be defined to present a pop-up.",
"By default tertiary button is not destructive. Use " + "[ exitlink ]".red() + " cta type to trigger a link (optional) and make it destructive for the pop-up.",
"In general if a call to action type is defined for a button, must be defined also the related payload. Except for the cta types " + "[ none | exitlink ]".red() + "."]
static let bannerSyntacticRules: [String] = ["At least one argument between" + " [ -title | -subtitle ] ".red() + "must be defined to present a banner.",
"In general if a call to action type is defined for a button, must be defined also the related payload."]
+ static let systemAlertSyntacticRules: [String] = ["At least one argument between" + " [ -title | -subtitle ] ".red() + "must be defined to present a systemAlert."]
static let popupNotes: [String] = ["If no call to action type defined for a button the default one is " + "[ none ]".red() + ", that simply return the exit code related to the clicked button.\n- \"/selected\" and \"/placeholder\" keys for " + "[ dropdown ]".red() + " accessory view payload are mutually exclusive."]
+ static let systemAlertNotes: [String] = ["If no call to action type defined for a button the default one is " + "[ none ]".red()]
static let bannerNotes: [String] = ["If no call to action type defined for a button the default one is " + "[ none ]".red() + ", that simply return the exit code related to the clicked button.\nAlert UI require additional configurations to work properly. Please refer to the related Github Wiki Page."]
static let specialArguments: [String] = ["--help".blue(),
"--version".blue(),
@@ -196,10 +228,11 @@ public final class HelpBuilder {
"239".bold()]
static let onboardingReturnValuesDescription: [String] = ["User did finish onboarding.",
"User dimissed the onboarding window."]
- static let examplePopup: String = "~/IBM\\ Notifier.app/Contents/MacOS/IBM\\ Notifier -type popup -title \"Test title\" -subtitle \"Test subtitle\" -accessory_view_type whitebox -accessory_view_payload \"Test accessory view\" -main_button_label \"Main button\" -secondary_button_label \"Secondary button\" -tertiary_button_label \"Tertiary button\" -tertiary_button_cta_type link -tertiary_button_cta_payload \"https://www.ibm.com\" -help_button_cta_type infopopup -help_button_cta_payload \"Test help text\"]"
+ static let examplePopup: String = "~/IBM\\ Notifier.app/Contents/MacOS/IBM\\ Notifier -type popup -title \"Test title\" -subtitle \"Test subtitle\" -accessory_view_type whitebox -accessory_view_payload \"Test accessory view\" -main_button_label \"Main button\" -secondary_button_label \"Secondary button\" -tertiary_button_label \"Tertiary button\" -tertiary_button_cta_type link -tertiary_button_cta_payload \"https://www.ibm.com\" -help_button_cta_type infopopup -help_button_cta_payload \"Test help text\""
static let exampleBanner: String = "~/IBM\\ Notifier.app/Contents/MacOS/IBM\\ Notifier -type banner -title \"Test title\" -subtitle \"Test subtitle\" -main_button_label \"Main button\" -secondary_button_label \"Secondary button\" -tertiary_button_label \"Tertiary button\" -tertiary_button_cta_type link -tertiary_button_cta_payload \"https://www.ibm.com\""
static let exampleAlert: String = "~/IBM\\ Notifier.app/Contents/MacOS/IBM\\ Notifier -type alert -title \"Test title\" -subtitle \"Test subtitle\" -main_button_label \"Main button\" -secondary_button_label \"Secondary button\" -tertiary_button_label \"Tertiary button\" -tertiary_button_cta_type link -tertiary_button_cta_payload \"https://www.ibm.com\""
static let exampleOnboarding: String = "~/IBM\\ Notifier.app/Contents/MacOS/IBM\\ Notifier -type onboarding -payload \"{\\\"pages\\\":[{\\\"title\\\":\\\"First page's title\\\",\\\"subtitle\\\":\\\"First page's subtitle\\\",\\\"body\\\":\\\"First page's body\\\"}]}\""
+ static let exampleSystemAlert: String = "~/IBM\\ Notifier.app/Contents/MacOS/IBM\\ Notifier -type popup -title \"Test title\" -subtitle \"Test subtitle\" -icon_path \"path/to/icon.png\" -main_button_label \"Main button\" -secondary_button_label \"Secondary button\" -tertiary_button_label \"Tertiary button\" -tertiary_button_cta_type link -tertiary_button_cta_payload \"https://www.ibm.com\" -silent -showSuppressionButton"
static func printHelp(_ arguments: [String]) {
guard !arguments.contains("-popup") else {
@@ -218,12 +251,16 @@ public final class HelpBuilder {
Self.printOnboardingHelp()
return
}
+ guard !arguments.contains("-systemAlert") else {
+ Self.printSystemAlertHelp()
+ return
+ }
guard !arguments.contains("-configuration") else {
Self.printConfigurationHelp()
return
}
print("\nIBM Notifier Help Page".bold().blue() + "\n")
- print("You can use:\n --help -popup - To show help page about the pop-up UI;\n --help -banner - To show help page about the banner (temporary banner notification) UI;\n --help -alert - To show help page about the alert (persistent banner notification) UI;\n --help -onboarding - To show help page about the onboarding UI;\n --help -configuration - To show help page about the configuration mode.\n")
+ print("You can use:\n --help -popup - To show help page about the pop-up UI;\n --help -banner - To show help page about the banner (temporary banner notification) UI;\n --help -alert - To show help page about the alert (persistent banner notification) UI;\n --help -onboarding - To show help page about the onboarding UI;\n --help -systemAlert - To show help page about the system alert UI;\n --help -configuration - To show help page about the configuration mode.\n")
}
static func printPopupHelp() {
@@ -319,6 +356,36 @@ public final class HelpBuilder {
}
}
+ static func printSystemAlertHelp() {
+ print("\nIBM Notifier System Alert UI".bold().blue() + "\n")
+ var argumentsString = ""
+ for argument in systemAlertArguments {
+ argumentsString += "[\(argument)] "
+ }
+ print("Usage: ".cyan().bold() + "\n~/IBM\\ Notifier.app/Contents/MacOS/IBM\\ Notifier " + argumentsString + "\n")
+ print("Color Legend: ".cyan().bold())
+ print("Mandatory value".green() + " " + "Optional value".yellow() + "\n")
+ print("Arguments details:".cyan().bold())
+ for index in systemAlertArguments.indices {
+ print("\(systemAlertArguments[index]): \(systemAlertDescriptions[index])")
+ }
+ print("\nSyntactic rules:".bold().cyan())
+ for index in systemAlertSyntacticRules.indices {
+ print("- \(systemAlertSyntacticRules[index])")
+ }
+ print("\nBe aware of:".bold().cyan())
+ for index in systemAlertNotes.indices {
+ print("- \(systemAlertNotes[index])")
+ }
+ print("\nReturn values:".bold().cyan())
+ for index in popupReturnValues.indices {
+ print("\(popupReturnValues[index]) - \(popupReturnValuesDescription[index])")
+ }
+ print("\nUsage examples:".bold().cyan())
+ print("- System Alert UI - ".blue() + exampleSystemAlert)
+ print("\n")
+ }
+
static func printNoArgumentsPage() {
print("\nIBM Notifier".bold().blue() + "\n")
for index in specialArguments.indices {
diff --git a/Notification Agent Core/Extensions/NotificationDispatch-Extension.swift b/Notification Agent Core/Extensions/NotificationDispatch-Extension.swift
index b184cbc..123bde2 100644
--- a/Notification Agent Core/Extensions/NotificationDispatch-Extension.swift
+++ b/Notification Agent Core/Extensions/NotificationDispatch-Extension.swift
@@ -28,7 +28,7 @@ extension NotificationDispatch {
taskManager.runAsyncTaskOnComponent(.banner, with: jsonData) { terminationStatus in
exit(terminationStatus)
}
- case .popup:
+ case .popup, .systemalert:
var isInteractive: Bool {
var int = false
object.notification.accessoryViews?.forEach({ accessoryView in
diff --git a/Notification Agent Core/Info.plist b/Notification Agent Core/Info.plist
index 1d19076..06c95d6 100644
--- a/Notification Agent Core/Info.plist
+++ b/Notification Agent Core/Info.plist
@@ -30,7 +30,7 @@
CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
+ 96
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/Notification Agent Onboarding/Info.plist b/Notification Agent Onboarding/Info.plist
index 3ea67e1..a76d44f 100644
--- a/Notification Agent Onboarding/Info.plist
+++ b/Notification Agent Onboarding/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
+ 96
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/Notification Agent Onboarding/Views/OnboardingPageViewController.swift b/Notification Agent Onboarding/Views/OnboardingPageViewController.swift
index eed1dd1..346fd0d 100644
--- a/Notification Agent Onboarding/Views/OnboardingPageViewController.swift
+++ b/Notification Agent Onboarding/Views/OnboardingPageViewController.swift
@@ -89,8 +89,8 @@ final class OnboardingPageViewController: NSViewController {
// MARK: - Instance methods
- override func viewWillAppear() {
- super.viewWillAppear()
+ override func viewDidLoad() {
+ super.viewDidLoad()
self.setupStackViewLayout()
self.setupButtonsLayout()
self.configureAccessibilityElements()
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/Contents.json b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/Contents.json
index 5dead08..7cf206c 100644
--- a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/Contents.json
+++ b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/Contents.json
@@ -1,8 +1,9 @@
{
"images" : [
{
- "filename" : "icon_512x512.png",
- "idiom" : "universal"
+ "filename" : "icon_128x128.png",
+ "idiom" : "universal",
+ "scale" : "1x"
},
{
"appearances" : [
@@ -11,8 +12,9 @@
"value" : "light"
}
],
- "filename" : "icon_512x512-1.png",
- "idiom" : "universal"
+ "filename" : "icon_128x128 1.png",
+ "idiom" : "universal",
+ "scale" : "1x"
},
{
"appearances" : [
@@ -21,8 +23,63 @@
"value" : "dark"
}
],
- "filename" : "icon_512x512-2.png",
- "idiom" : "universal"
+ "filename" : "icon_128x128 2.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "icon_128x128@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "light"
+ }
+ ],
+ "filename" : "icon_128x128@2x 1.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "icon_128x128@2x 2.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "icon_128x128@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "light"
+ }
+ ],
+ "filename" : "icon_128x128@3x 1.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "icon_128x128@3x 2.png",
+ "idiom" : "universal",
+ "scale" : "3x"
}
],
"info" : {
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128 1.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128 1.png
new file mode 100644
index 0000000..ebb3f96
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128 1.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128 2.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128 2.png
new file mode 100644
index 0000000..ebb3f96
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128 2.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128.png
new file mode 100644
index 0000000..ebb3f96
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x 1.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x 1.png
new file mode 100644
index 0000000..63ff287
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x 1.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x 2.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x 2.png
new file mode 100644
index 0000000..63ff287
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x 2.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x.png
new file mode 100644
index 0000000..63ff287
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@2x.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x 1.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x 1.png
new file mode 100644
index 0000000..f8a7bba
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x 1.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x 2.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x 2.png
new file mode 100644
index 0000000..f8a7bba
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x 2.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x.png
new file mode 100644
index 0000000..f8a7bba
Binary files /dev/null and b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_128x128@3x.png differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512-1.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512-1.png
deleted file mode 100644
index 6209152..0000000
Binary files a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512-1.png and /dev/null differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512-2.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512-2.png
deleted file mode 100644
index 6209152..0000000
Binary files a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512-2.png and /dev/null differ
diff --git a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512.png b/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512.png
deleted file mode 100644
index 6209152..0000000
Binary files a/Notification Agent Popups/Assets.xcassets/Common/default_icon.imageset/icon_512x512.png and /dev/null differ
diff --git a/Notification Agent Popups/Controllers/SystemAlertController.swift b/Notification Agent Popups/Controllers/SystemAlertController.swift
new file mode 100644
index 0000000..504a71a
--- /dev/null
+++ b/Notification Agent Popups/Controllers/SystemAlertController.swift
@@ -0,0 +1,116 @@
+//
+// SystemAlertController.swift
+// Notification Agent
+//
+// Created by Simone Martorelli on 17/08/22.
+// Copyright © 2022 IBM. All rights reserved.
+// SPDX-License-Identifier: Apache2.0
+//
+
+import Foundation
+import AppKit
+
+/// Handle the systemAlert UIs appearance and behavior.
+final class SystemAlertController {
+
+ // MARK: - Variables
+
+ let notificationObject: NotificationObject
+ let alert: NSAlert
+ var suppressNotification: Bool
+
+ // MARK: - Initializers
+
+ init(_ object: NotificationObject) {
+ notificationObject = object
+ alert = NSAlert()
+ suppressNotification = false
+ setupAlert()
+ }
+
+ // MARK: - Private Methods
+
+ /// Setup the alert layout, components and appearance.
+ private func setupAlert() {
+ alert.alertStyle = .informational
+
+ // Setting up labels.
+ alert.messageText = notificationObject.title ?? ""
+ alert.informativeText = notificationObject.subtitle ?? ""
+
+ // Setting up alert icon.
+ if let iconPath = notificationObject.iconPath {
+ if FileManager.default.fileExists(atPath: iconPath),
+ let data = try? Data(contentsOf: URL(fileURLWithPath: iconPath)) {
+ let image = NSImage(data: data)
+ alert.icon = image
+ } else if iconPath.isValidURL,
+ let url = URL(string: iconPath),
+ let data = try? Data(contentsOf: url) {
+ let image = NSImage(data: data)
+ alert.icon = image
+ } else if let imageData = Data(base64Encoded: iconPath, options: .ignoreUnknownCharacters),
+ let image = NSImage(data: imageData) {
+ alert.icon = image
+ } else {
+ NALogger.shared.log("Unable to load image from %{public}@", [iconPath])
+ }
+ }
+
+ // Setting up buttons.
+ let mainButton = alert.addButton(withTitle: notificationObject.mainButton.label)
+ mainButton.action = #selector(self.didPressMainButton(_:))
+ mainButton.target = self
+ if let secondaryButton = notificationObject.secondaryButton {
+ let secondaryButton = alert.addButton(withTitle: secondaryButton.label)
+ secondaryButton.action = #selector(self.didPressSecondaryButton(_:))
+ secondaryButton.target = self
+ }
+ if let tertiaryButton = notificationObject.tertiaryButton {
+ let tertiaryButton = alert.addButton(withTitle: tertiaryButton.label)
+ tertiaryButton.action = #selector(self.didPressTertiaryButton(_:))
+ tertiaryButton.target = self
+ }
+
+ // Setting up help button.
+ alert.showsHelp = false
+
+ // Setting up suppression button.
+ alert.showsSuppressionButton = notificationObject.showSuppressionButton ?? false
+ alert.suppressionButton?.action = #selector(didPressSuppressButton(_:))
+ alert.suppressionButton?.target = self
+ }
+
+ // MARK: - Public Methods
+
+ /// Show the alert to the end user.
+ func showAlert() {
+ if !(notificationObject.silent ?? false) {
+ NSSound(named: .init("Funk"))?.play()
+ }
+ alert.runModal()
+ alert.window.setWindowPosition(notificationObject.position ?? .center)
+ }
+
+ // MARK: - Actions
+
+ @objc
+ private func didPressMainButton(_ sender: NSButton) {
+ if suppressNotification { print("suppress") }
+ ReplyHandler.shared.handleResponse(ofType: .main, for: notificationObject)
+ }
+ @objc
+ private func didPressSecondaryButton(_ sender: NSButton) {
+ if suppressNotification { print("suppress") }
+ ReplyHandler.shared.handleResponse(ofType: .secondary, for: notificationObject)
+ }
+ @objc
+ private func didPressTertiaryButton(_ sender: NSButton) {
+ if suppressNotification { print("suppress") }
+ ReplyHandler.shared.handleResponse(ofType: .tertiary, for: notificationObject)
+ }
+ @objc
+ private func didPressSuppressButton(_ sender: NSButton) {
+ suppressNotification = sender.state == .on
+ }
+}
diff --git a/Notification Agent Popups/Extensions/NotificationDispatch-Extension.swift b/Notification Agent Popups/Extensions/NotificationDispatch-Extension.swift
index a7e1a69..54d0025 100644
--- a/Notification Agent Popups/Extensions/NotificationDispatch-Extension.swift
+++ b/Notification Agent Popups/Extensions/NotificationDispatch-Extension.swift
@@ -16,22 +16,32 @@ extension NotificationDispatch {
@objc
func receivedNotification(_ notification: Notification) {
guard let object = notification.userInfo?["object"] as? NotificationObject else { return }
- DispatchQueue.main.async {
- let storyboard = NSStoryboard(name: "Main", bundle: nil)
- guard let popUpViewController = storyboard.instantiateController(withIdentifier: PopUpViewController.identifier) as? PopUpViewController else { return }
- popUpViewController.notificationObject = object
- let window = NSWindow(contentViewController: popUpViewController)
- if object.forceLightMode ?? false {
- window.appearance = NSAppearance(named: .aqua)
+ switch object.type {
+ case .systemalert:
+ DispatchQueue.main.async {
+ let alertController = SystemAlertController(object)
+ alertController.showAlert()
}
- window.styleMask.remove(.resizable)
- if !(object.isMiniaturizable ?? false) {
- window.styleMask.remove(.miniaturizable)
+ case .popup:
+ DispatchQueue.main.async {
+ let storyboard = NSStoryboard(name: "Main", bundle: nil)
+ guard let popUpViewController = storyboard.instantiateController(withIdentifier: PopUpViewController.identifier) as? PopUpViewController else { return }
+ popUpViewController.notificationObject = object
+ let window = NSWindow(contentViewController: popUpViewController)
+ if object.forceLightMode ?? false {
+ window.appearance = NSAppearance(named: .aqua)
+ }
+ window.styleMask.remove(.resizable)
+ if !(object.isMiniaturizable ?? false) {
+ window.styleMask.remove(.miniaturizable)
+ }
+ window.styleMask.remove(.closable)
+ window.makeKeyAndOrderFront(self)
+ guard object.silent == false else { return }
+ NSSound(named: .init("Funk"))?.play()
}
- window.styleMask.remove(.closable)
- window.makeKeyAndOrderFront(self)
- guard object.silent == false else { return }
- NSSound(named: .init("Funk"))?.play()
+ default:
+ Utils.applicationExit(withReason: .internalError)
}
}
}
diff --git a/Notification Agent Popups/Info.plist b/Notification Agent Popups/Info.plist
index 3ea67e1..a76d44f 100644
--- a/Notification Agent Popups/Info.plist
+++ b/Notification Agent Popups/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
+ 96
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/Notification Agent Popups/Views/PopUpViewController.swift b/Notification Agent Popups/Views/PopUpViewController.swift
index fb1981b..777ff51 100644
--- a/Notification Agent Popups/Views/PopUpViewController.swift
+++ b/Notification Agent Popups/Views/PopUpViewController.swift
@@ -206,7 +206,6 @@ class PopUpViewController: NSViewController {
self.popupElementsStackView.insertView(progressBarAccessoryView, at: 0, in: .center)
progressBarAccessoryView.progressBarDelegate = self
progressBarAccessoryView.delegate = self
- progressBarAccessoryView.startObservingForUpdates()
self.accessoryViews.append(progressBarAccessoryView)
self.shouldAllowCancel = progressBarAccessoryView.isUserInterruptionAllowed
case .image:
diff --git a/Notification Agent.xcodeproj/project.pbxproj b/Notification Agent.xcodeproj/project.pbxproj
index be89606..ac56674 100644
--- a/Notification Agent.xcodeproj/project.pbxproj
+++ b/Notification Agent.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 53;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -247,6 +247,8 @@
B9EDC98E24EC0D91004F6108 /* InfoSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9EDC98D24EC0D91004F6108 /* InfoSection.swift */; };
F47F553E249B8C1B006A0754 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F47F553D249B8C1B006A0754 /* Assets.xcassets */; };
F47F5541249B8C1B006A0754 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F47F553F249B8C1B006A0754 /* Main.storyboard */; };
+ FD0D02D528D9F8AE00A167B7 /* SystemAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0D02D428D9F8AE00A167B7 /* SystemAlertController.swift */; };
+ FD0D02D628D9F8AE00A167B7 /* SystemAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0D02D428D9F8AE00A167B7 /* SystemAlertController.swift */; };
FD1730032875B02F00781A69 /* OnboardingInteractiveEFCLController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1730022875B02F00781A69 /* OnboardingInteractiveEFCLController.swift */; };
FD1730042875B02F00781A69 /* OnboardingInteractiveEFCLController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1730022875B02F00781A69 /* OnboardingInteractiveEFCLController.swift */; };
FD1730072875B0D200781A69 /* PopupInteractiveEFCLController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1730062875B0D200781A69 /* PopupInteractiveEFCLController.swift */; };
@@ -750,6 +752,7 @@
F47F553D249B8C1B006A0754 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
F47F5540249B8C1B006A0754 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
F47F5542249B8C1B006A0754 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ FD0D02D428D9F8AE00A167B7 /* SystemAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemAlertController.swift; sourceTree = ""; };
FD1730022875B02F00781A69 /* OnboardingInteractiveEFCLController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingInteractiveEFCLController.swift; sourceTree = ""; };
FD1730062875B0D200781A69 /* PopupInteractiveEFCLController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupInteractiveEFCLController.swift; sourceTree = ""; };
FD1730092875B82000781A69 /* DynamicNotificationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicNotificationButton.swift; sourceTree = ""; };
@@ -970,6 +973,7 @@
B961A5B4267B451400657930 /* Main.storyboard */,
B961A62B267C9DA200657930 /* Assets.xcassets */,
FD1730062875B0D200781A69 /* PopupInteractiveEFCLController.swift */,
+ FD0D02D728D9F8B500A167B7 /* Controllers */,
B9360EBA268A04A900217247 /* Extensions */,
B961A5F8267B8B7800657930 /* Views */,
);
@@ -1210,6 +1214,14 @@
path = "Notification Agent Core";
sourceTree = "";
};
+ FD0D02D728D9F8B500A167B7 /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ FD0D02D428D9F8AE00A167B7 /* SystemAlertController.swift */,
+ );
+ path = Controllers;
+ sourceTree = "";
+ };
FD1730052875B04600781A69 /* Controllers */ = {
isa = PBXGroup;
children = (
@@ -1369,7 +1381,7 @@
isa = PBXNativeTarget;
buildConfigurationList = F47F555C249B8C1C006A0754 /* Build configuration list for PBXNativeTarget "IBM Notifier" */;
buildPhases = (
- B9710AB424A0A584000B5A67 /* ShellScript */,
+ B9710AB424A0A584000B5A67 /* SwiftLint */,
F47F5532249B8C1B006A0754 /* Sources */,
F47F5533249B8C1B006A0754 /* Frameworks */,
F47F5534249B8C1B006A0754 /* Resources */,
@@ -1743,8 +1755,9 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- B9710AB424A0A584000B5A67 /* ShellScript */ = {
+ B9710AB424A0A584000B5A67 /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -1752,6 +1765,7 @@
);
inputPaths = (
);
+ name = SwiftLint;
outputFileListPaths = (
);
outputPaths = (
@@ -1864,6 +1878,7 @@
B961A52B267A4D8F00657930 /* DropDownAccessoryView.swift in Sources */,
B961A533267A4DC700657930 /* HorizontalLine.swift in Sources */,
B961A50F267A4D3C00657930 /* Environment.swift in Sources */,
+ FD0D02D528D9F8AE00A167B7 /* SystemAlertController.swift in Sources */,
B961A527267A4D8F00657930 /* HTMLAccessoryView.swift in Sources */,
FD1730182875B9A000781A69 /* InteractiveObjectProtocol.swift in Sources */,
);
@@ -2184,6 +2199,7 @@
FDC3474B2858C4E8001F2212 /* PopUpViewController.swift in Sources */,
FDC346A72858C42A001F2212 /* ReplyHandler.swift in Sources */,
FDC346E12858C459001F2212 /* UserReplyType.swift in Sources */,
+ FD0D02D628D9F8AE00A167B7 /* SystemAlertController.swift in Sources */,
FDC347062858C476001F2212 /* InfoPopOverStackItem.swift in Sources */,
FDC347292858C494001F2212 /* Decodable-Extensions.swift in Sources */,
FDC3473E2858C4AF001F2212 /* InteractiveEFCLContoller.swift in Sources */,
@@ -2428,7 +2444,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Alerts/Info.plist";
@@ -2437,13 +2453,14 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.alert;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
@@ -2456,7 +2473,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Alerts/Info.plist";
@@ -2465,13 +2482,14 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.alert;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
@@ -2484,7 +2502,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Popups/Info.plist";
@@ -2493,13 +2511,14 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.popup;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
@@ -2512,7 +2531,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Popups/Info.plist";
@@ -2521,13 +2540,14 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.popup;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
@@ -2540,7 +2560,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Onboarding/Info.plist";
@@ -2549,12 +2569,13 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.onboarding;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
@@ -2567,7 +2588,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Onboarding/Info.plist";
@@ -2576,12 +2597,13 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.onboarding;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
@@ -2594,7 +2616,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Banners/Info.plist";
@@ -2603,13 +2625,14 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.banner;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
@@ -2622,7 +2645,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Notification Agent Banners/Info.plist";
@@ -2631,13 +2654,14 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier.banner;
PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
@@ -2675,6 +2699,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 97;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@@ -2694,6 +2719,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
+ MARKETING_VERSION = 2.9.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -2737,6 +2763,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 97;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -2750,6 +2777,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
+ MARKETING_VERSION = 2.9.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
@@ -2767,7 +2795,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GCC_GENERATE_TEST_COVERAGE_FILES = YES;
@@ -2777,12 +2805,13 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
@@ -2795,7 +2824,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 87;
+ CURRENT_PROJECT_VERSION = 97;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GCC_GENERATE_TEST_COVERAGE_FILES = YES;
@@ -2805,12 +2834,13 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
- MARKETING_VERSION = 2.8.0;
+ MARKETING_VERSION = 2.9.1;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.ibm.cio.notifier;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
@@ -2820,7 +2850,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2841,7 +2871,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2862,7 +2892,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2883,7 +2913,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2904,7 +2934,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2925,7 +2955,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2946,7 +2976,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2967,7 +2997,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -2987,7 +3017,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -3007,7 +3037,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -3028,7 +3058,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -3049,7 +3079,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Manual;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
DEVELOPMENT_TEAM = "";
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -3069,7 +3099,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
@@ -3087,7 +3117,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 96;
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
diff --git a/Shared/Controllers/EFCLController.swift b/Shared/Controllers/EFCLController.swift
index 9167090..7e1b6e3 100644
--- a/Shared/Controllers/EFCLController.swift
+++ b/Shared/Controllers/EFCLController.swift
@@ -33,8 +33,9 @@ final class EFCLController {
"miniaturizable",
"force_light_mode",
"hide_title_bar_buttons",
- "retain_values"
- ]
+ "retain_values",
+ "retain_values",
+ "show_suppression_button"]
// MARK: - Variables
diff --git a/Shared/Model/UIObjects/NotificationObject.swift b/Shared/Model/UIObjects/NotificationObject.swift
index 8880035..35999ea 100644
--- a/Shared/Model/UIObjects/NotificationObject.swift
+++ b/Shared/Model/UIObjects/NotificationObject.swift
@@ -22,6 +22,7 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
case banner // Temporary user notification banner.
case onboarding // Onboarding window.
case alert // Persistent user notification banner.
+ case systemalert // Standard system Alert pop-up.
}
/// A set of predefined workflow
@@ -92,6 +93,8 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
var hideTitleBarButtons: Bool?
/// A boolean value that define if to print the available accessory view outputs on the secondary button click.
var retainValues: Bool?
+ /// A boolean value that define if to show the suppress notification checkbox on the systemAlert UI. Works only with systemAlert UI type.
+ var showSuppressionButton: Bool?
/// If defined the app should just run the predefined workflow
var workflow: PredefinedWorkflow?
@@ -206,6 +209,11 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
} else {
self.retainValues = false
}
+ if let showSuppressionButtonRaw = dict["show_suppression_button"] as? String {
+ self.showSuppressionButton = showSuppressionButtonRaw.lowercased() == "true"
+ } else {
+ self.showSuppressionButton = false
+ }
if let positionRaw = dict["position"] as? String {
self.position = NSWindow.WindowPosition(rawValue: positionRaw)
}
@@ -222,7 +230,7 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
private func checkObjectConsistency() throws {
switch type {
- case .popup, .banner, .alert:
+ case .popup, .banner, .alert, .systemalert:
guard self.title != nil || self.subtitle != nil || !(self.accessoryViews?.isEmpty ?? true) || self.workflow != nil else {
throw NAError.dataFormat(type: .noInfoToShow)
}
@@ -308,6 +316,7 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
case popupReminder
case hideTitleBarButtons
case retainValues
+ case showSuppressionButton
case workflow
}
@@ -340,6 +349,7 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
self.hideTitleBarButtons = try container.decodeIfPresent(Bool.self, forKey: .hideTitleBarButtons)
self.forceLightMode = try container.decodeIfPresent(Bool.self, forKey: .forceLightMode)
self.retainValues = try container.decodeIfPresent(Bool.self, forKey: .retainValues)
+ self.showSuppressionButton = try container.decodeIfPresent(Bool.self, forKey: .showSuppressionButton)
self.payload = try container.decodeIfPresent(OnboardingData.self, forKey: .payload)
if let positionRawValue = try container.decodeIfPresent(String.self, forKey: .position) {
self.position = NSWindow.WindowPosition(rawValue: positionRawValue)
@@ -377,6 +387,7 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
try container.encodeIfPresent(self.hideTitleBarButtons, forKey: .hideTitleBarButtons)
try container.encodeIfPresent(self.forceLightMode, forKey: .forceLightMode)
try container.encodeIfPresent(self.retainValues, forKey: .retainValues)
+ try container.encodeIfPresent(self.showSuppressionButton, forKey: .showSuppressionButton)
try container.encodeIfPresent(self.payload, forKey: .payload)
try container.encodeIfPresent(self.position?.rawValue, forKey: .position)
try container.encodeIfPresent(self.popupReminder, forKey: .popupReminder)
@@ -459,6 +470,10 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
let number = NSNumber(booleanLiteral: retainValues)
coder.encode(number, forKey: NOCodingKeys.retainValues.rawValue)
}
+ if let showSuppressionButton = self.showSuppressionButton {
+ let number = NSNumber(booleanLiteral: showSuppressionButton)
+ coder.encode(number, forKey: NOCodingKeys.showSuppressionButton.rawValue)
+ }
if let position = self.position?.rawValue {
coder.encode(position, forKey: NOCodingKeys.position.rawValue)
}
@@ -496,6 +511,7 @@ public final class NotificationObject: NSObject, Codable, NSSecureCoding {
self.hideTitleBarButtons = coder.decodeObject(of: NSNumber.self, forKey: NOCodingKeys.hideTitleBarButtons.rawValue) as? Bool
self.forceLightMode = coder.decodeObject(of: NSNumber.self, forKey: NOCodingKeys.forceLightMode.rawValue) as? Bool
self.retainValues = coder.decodeObject(of: NSNumber.self, forKey: NOCodingKeys.retainValues.rawValue) as? Bool
+ self.showSuppressionButton = coder.decodeObject(of: NSNumber.self, forKey: NOCodingKeys.showSuppressionButton.rawValue) as? Bool
if let positionRawValue = coder.decodeObject(of: NSString.self, forKey: NOCodingKeys.position.rawValue) {
self.position = NSWindow.WindowPosition(rawValue: positionRawValue as String)
}
diff --git a/Shared/Views/AccessoryViews/HTMLAccessoryView.swift b/Shared/Views/AccessoryViews/HTMLAccessoryView.swift
index b615162..0df9f4a 100644
--- a/Shared/Views/AccessoryViews/HTMLAccessoryView.swift
+++ b/Shared/Views/AccessoryViews/HTMLAccessoryView.swift
@@ -153,7 +153,7 @@ final class HTMLAccessoryView: AccessoryView {
let newHtml = #""# + html + ""
let data = Data(newHtml.utf8)
do {
- let attributedString = try NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .defaultAttributes: defaultAttributes], documentAttributes: nil)
+ let attributedString = try NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .defaultAttributes: defaultAttributes, .textEncodingName: "UTF8"], documentAttributes: nil)
self.textView.textStorage?.setAttributedString(attributedString)
} catch {
NALogger.shared.log("Unable to parse the given HTML. No text will be shown. %{public}@", [error.localizedDescription])
diff --git a/Shared/Views/AccessoryViews/InputAccessoryView.swift b/Shared/Views/AccessoryViews/InputAccessoryView.swift
index 33747f7..3bce9c1 100644
--- a/Shared/Views/AccessoryViews/InputAccessoryView.swift
+++ b/Shared/Views/AccessoryViews/InputAccessoryView.swift
@@ -66,6 +66,7 @@ class InputAccessoryView: AccessoryView {
override func adjustViewSize() {
inputTextField.widthAnchor.constraint(equalToConstant: containerWidth).isActive = true
+ adjustTextAreaHeight()
}
override func configureAccessibilityElements() {
@@ -109,6 +110,7 @@ class InputAccessoryView: AccessoryView {
fieldTopAnchor.isActive = false
fieldTopAnchor = inputTextField.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 4)
fieldTopAnchor.isActive = true
+ fieldTopAnchor.priority = .defaultHigh
hasTitle = true
case "placeholder":
self.inputTextField.placeholderString = value
@@ -125,17 +127,22 @@ class InputAccessoryView: AccessoryView {
}
self.mainButtonState = (self.isRequired && self.inputTextField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty) ? .disabled : .enabled
}
-}
-
-extension InputAccessoryView: NSTextFieldDelegate {
- func controlTextDidChange(_ obj: Notification) {
- self.mainButtonState = (inputTextField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && isRequired) ? .disabled : .enabled
+
+ private func adjustTextAreaHeight() {
let height = inputTextField.sizeThatFits(NSSize(width: inputTextField.bounds.width, height: 0)).height
if height != inputTextField.bounds.height && !preventResize {
self.textFieldHeightAnchor?.isActive = false
self.textFieldHeightAnchor = self.inputTextField.heightAnchor.constraint(equalToConstant: min(height, 200))
self.textFieldHeightAnchor.isActive = true
+ self.textFieldHeightAnchor.priority = .required
}
+ }
+}
+
+extension InputAccessoryView: NSTextFieldDelegate {
+ func controlTextDidChange(_ obj: Notification) {
+ self.mainButtonState = (inputTextField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && isRequired) ? .disabled : .enabled
+ self.adjustTextAreaHeight()
delegate?.accessoryViewStatusDidChange(self)
}
}
diff --git a/Shared/Views/AccessoryViews/ProgressBarAccessoryView.swift b/Shared/Views/AccessoryViews/ProgressBarAccessoryView.swift
index 3a81696..70b6d9d 100644
--- a/Shared/Views/AccessoryViews/ProgressBarAccessoryView.swift
+++ b/Shared/Views/AccessoryViews/ProgressBarAccessoryView.swift
@@ -59,7 +59,7 @@ class ProgressBarAccessoryView: AccessoryView, InteractiveObjectProtocol {
}
deinit {
- NotificationCenter.default.removeObserver(self, name: Notification.Name(self.objectIdentifier), object: nil)
+ NotificationCenter.default.removeObserver(self)
}
// MARK: - Instance methods