Skip to content

Commit 32c8bb9

Browse files
committed
feat(popup): support for more than 2 accessory views
1 parent 7ccbb26 commit 32c8bb9

File tree

5 files changed

+167
-148
lines changed

5 files changed

+167
-148
lines changed

Notification Agent Core/Controllers/HelpBuilder.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public final class HelpBuilder {
2020
"-icon_height".yellow(),
2121
"-accessory_view_type".yellow(),
2222
"-accessory_view_payload".yellow(),
23-
"-secondary_accessory_view_type".yellow(),
24-
"-secondary_accessory_view_payload".yellow(),
23+
"-accessory_view_type_N".yellow(),
24+
"-accessory_view_payload_N".yellow(),
2525
"-main_button_label".yellow(),
2626
"-main_button_cta_type".yellow(),
2727
"-main_button_cta_payload".yellow(),
@@ -112,8 +112,8 @@ public final class HelpBuilder {
112112
"Example 3: -accessory_view_payload \"/percent indeterminate /top_message This is the top message /bottom_message This is the bottom message\";\n " +
113113
"Example 4: -accessory_view_payload \"<h1>Hello, world!</h1>this is a line of text<br><br><code>this is a code block<br>this is the second line of a code block</code><br>this is <span style=\"color: #ff0000\">red</span> text\"\n " +
114114
"Example 5: -accessory_view_payload \"/images /path/to/image.jpg\\nhttps://www.url.to/image.png\\nhttps://www.url.to/image.png /autoplay /delay 3\".",
115-
"\n Same as for accessory_view_type argument.",
116-
"\n Same as for accessory_view_payload argument.",
115+
"\n Same as for accessory_view_type argument. The tool support multiple accessory views on each pop-up;\n Example 1: accessory_view_type_1 image;\n Example 2: accessory_view_type_2 dropdown;",
116+
"\n Same as for accessory_view_payload argument. The tool support multiple accessory views on each pop-up;\n Example 1: accessory_view_payload_1 \"path/or/URL/to/file\";\n Example 2: accessory_view_payload_2 \"/list One\\nTwo\\nThree\";",
117117
"\n The label of the main button.\n Example: -main_button_label \"Main button title\"",
118118
"[ none | link ]".red() + "\n The call to action type for the main button (default: none -> exit).\n Example: -main_button_cta_type link",
119119
"\n An URL if " + "[ link ]".red() + " cta type defined.\n Example: -main_button_cta_payload \"URL\"",
@@ -180,7 +180,8 @@ public final class HelpBuilder {
180180
"\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"]
181181
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.",
182182
"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.",
183-
"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() + "."]
183+
"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() + ".",
184+
"To setup multiple accessory views on the pop-up use \"-accessory_view_type_N\" and \"-accessory_view_payload_N\" where N is an integer number that goes from 1 to 100. Use only sequential integers (CORRECT: 1, 2 ,3, 4, ... | WRONG: 1, 3, 5, 6, ...)."]
184185
static let bannerSyntacticRules: [String] = ["At least one argument between" + " [ -title | -subtitle ] ".red() + "must be defined to present a banner.",
185186
"In general if a call to action type is defined for a button, must be defined also the related payload."]
186187
static let systemAlertSyntacticRules: [String] = ["At least one argument between" + " [ -title | -subtitle ] ".red() + "must be defined to present a systemAlert."]

Notification Agent Popup UI Tests/NAPUITests.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,5 +1165,59 @@ class NAPUITests: XCTestCase {
11651165
XCTAssert(false, "Failed to encode the usecase.")
11661166
}
11671167
}
1168+
1169+
/// Testing Pop-up with:
1170+
/// Title: This is a title
1171+
/// Subtitle: This is a subtitle
1172+
/// Main Button: Primary
1173+
/// Secondary Button: Secondary
1174+
/// AccessoryView: dropdown
1175+
/// AccessoryView1: datepicker
1176+
/// AccessoryView2: whitebox
1177+
/// AccessoryView3: GIF
1178+
/// AccessoryView4: image
1179+
func testE1Popup() throws {
1180+
let useCase = """
1181+
{"notification":{"topicID":"untracked","mainButton":{"label":"Primary","callToActionType":"none","callToActionPayload":""},"secondaryButton":{"label":"Secondary","callToActionType":"none","callToActionPayload":""},"hideTitleBarButtons":false,"retainValues":false,"alwaysOnTop":false,"type":"popup","title":"This is a title","subtitle":"This is a subtitle","silent":false,"showSuppressionButton":false,"miniaturizable":false,"barTitle":"Some","forceLightMode":false,"notificationID":"untracked","isMovable":true,"disableQuit":false,"buttonless":false,"hideTitleBar":false, "accessoryViews":[{"type":"dropdown","payload":"/list First\\nSecond\\nThird /placeholder Pick something /title Some title"},{"type":"datepicker","payload":"/title Some title /style graphical /components date"},{"type":"whitebox","payload":"Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view"},{"type":"image","payload":"https://compote.slate.com/images/697b023b-64a5-49a0-8059-27b963453fb1.gif?crop=780%2C520%2Cx0%2Cy0&width=2200"},{"type":"image","payload":"https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_1280.jpg"}]},"settings":{"isVerboseModeEnabled":false,"environment":"prod"}}
1182+
""" // pragma: allowlist-secret
1183+
if let useCaseData = useCase.data(using: .utf8) {
1184+
let app = XCUIApplication()
1185+
app.launchArguments = [useCaseData.base64EncodedString()]
1186+
app.launch()
1187+
XCTAssert(app.buttons["main_button"].exists)
1188+
XCTAssertEqual(app.buttons["main_button"].title, "Primary")
1189+
XCTAssert(app.buttons["secondary_button"].exists)
1190+
XCTAssertEqual(app.buttons["secondary_button"].label, "Secondary")
1191+
XCTAssert(app.staticTexts["popup_title"].exists)
1192+
XCTAssertEqual(app.staticTexts["popup_title"].value as? String ?? "", "This is a title")
1193+
XCTAssert(app.staticTexts["popup_subtitle"].exists)
1194+
XCTAssertEqual(app.staticTexts["popup_subtitle"].value as? String ?? "", "This is a subtitle")
1195+
XCTAssertEqual(app.staticTexts["picker_accessory_view_title"].value as? String ?? "", "Some title")
1196+
XCTAssert(app.popUpButtons["picker_accessory_view_dropdown"].exists)
1197+
XCTAssertEqual(app.popUpButtons["picker_accessory_view_dropdown"].value as? String, "Pick something")
1198+
app.popUpButtons["picker_accessory_view_dropdown"].click()
1199+
XCTAssert(app.popUpButtons["picker_accessory_view_dropdown"].menuItems["First"].exists)
1200+
app.popUpButtons["picker_accessory_view_dropdown"].menuItems["First"].click()
1201+
sleep(1)
1202+
XCTAssertEqual(app.popUpButtons["picker_accessory_view_dropdown"].value as? String, "First")
1203+
app.popUpButtons["picker_accessory_view_dropdown"].click()
1204+
XCTAssert(app.popUpButtons["picker_accessory_view_dropdown"].menuItems["Second"].exists)
1205+
app.popUpButtons["picker_accessory_view_dropdown"].menuItems["Second"].click()
1206+
sleep(1)
1207+
XCTAssertEqual(app.popUpButtons["picker_accessory_view_dropdown"].value as? String, "Second")
1208+
XCTAssert(app.staticTexts["datepicker_accessory_view_title"].exists)
1209+
XCTAssertEqual(app.staticTexts["datepicker_accessory_view_title"].value as? String ?? "", "Some title")
1210+
XCTAssert(app.datePickers["datepicker_accessory_view_picker"].exists)
1211+
XCTAssert(app.datePickers["datepicker_accessory_view_picker"].isEnabled)
1212+
XCTAssertNotNil(app.datePickers["datepicker_accessory_view_picker"].value)
1213+
XCTAssert(app.textViews["markdown_accessory_view"].exists)
1214+
XCTAssertEqual(app.textViews["markdown_accessory_view"].value as? String ?? "", "Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view Some text in the whitebox accessory view")
1215+
XCTAssert(app.images["image_accessory_view"].exists)
1216+
XCTAssert(app.staticTexts["picker_accessory_view_title"].exists)
1217+
app.terminate()
1218+
} else {
1219+
XCTAssert(false, "Failed to encode the usecase.")
1220+
}
1221+
}
11681222
}
11691223
// swiftlint:enable type_body_length file_length

Notification Agent Popups/Views/PopUpView.swift

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,26 +54,19 @@ struct PopUpView: View {
5454
subtitle: viewModel.notificationObject.subtitle)
5555
.environmentObject(viewModel.viewSpec)
5656
.padding(.bottom, 8)
57-
if let primaryAV = viewModel.primaryAccessoryView {
58-
switch primaryAV.accessoryView.type {
59-
case .timer:
60-
Text($viewModel.primaryAVInput.wrappedValue.localized)
61-
.fixedSize(horizontal: false, vertical: true)
62-
.accessibilityIdentifier("timer_accessory_view")
63-
default:
64-
AccessoryViewWrapper(source: primaryAV)
65-
.environmentObject(viewModel.viewSpec)
66-
}
67-
}
68-
if let secondaryAV = viewModel.secondaryAccessoryView {
69-
switch secondaryAV.accessoryView.type {
70-
case .timer:
71-
Text($viewModel.secondaryAVInput.wrappedValue.localized)
72-
.fixedSize(horizontal: false, vertical: true)
73-
.accessibilityIdentifier("timer_accessory_view")
74-
default:
75-
AccessoryViewWrapper(source: secondaryAV)
76-
.environmentObject(viewModel.viewSpec)
57+
if !viewModel.accessoryViews.isEmpty {
58+
VStack(alignment: .leading) {
59+
ForEach(viewModel.accessoryViews, id: \.hashValue) { accessoryView in
60+
switch accessoryView.source.accessoryView.type {
61+
case .timer:
62+
Text($viewModel.timerAVInput.wrappedValue.localized)
63+
.fixedSize(horizontal: false, vertical: true)
64+
.accessibilityIdentifier("timer_accessory_view")
65+
default:
66+
accessoryView
67+
.environmentObject(viewModel.viewSpec)
68+
}
69+
}
7770
}
7871
}
7972
Spacer(minLength: 12)
@@ -91,7 +84,7 @@ struct PopUpView: View {
9184
.accessibilityIdentifier("secondary_button")
9285
StandardButton(keyboardShortcut: .return, action: {
9386
self.viewModel.didClickButton(of: .main)
94-
}, label: viewModel.notificationObject.mainButton.label, buttonState: $viewModel.mainButtonState)
87+
}, label: viewModel.notificationObject.mainButton.label, buttonState: $viewModel.primaryButtonState)
9588
.accessibilityHint(viewModel.notificationObject.mainButton.callToActionType.accessibilityHint)
9689
.accessibilityIdentifier("main_button")
9790
}

0 commit comments

Comments
 (0)