Skip to content

Commit

Permalink
Simplified notification content.
Browse files Browse the repository at this point in the history
  • Loading branch information
erikdoe committed Jan 21, 2024
1 parent b814794 commit 87a45da
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 76 deletions.
101 changes: 47 additions & 54 deletions CCMenu/Source/Notifications/NotificationFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,67 +21,40 @@ public enum NotificationType: String {
class NotificationFactory {

func notificationContent(change: StatusChange) -> UNNotificationContent? {
var content = UNMutableNotificationContent()
switch change.kind {
case .start:
return notificationContentForStarted(change: change)
if !shouldSendStartNotification(change: change) {
return nil
}
addContentForStartedNotification(content, change: change)
case .completion:
return notificationContentForFinished(change: change)
if !shouldSendFinishedNotification(change: change) {
return nil
}
addContentForFinishedNotification(content, change: change)
default:
return nil
}
}

private func notificationContentForStarted(change: StatusChange) -> UNNotificationContent? {
if !UserDefaults.active.bool(forKey: DefaultsKey.key(forNotification: .started)) {
return nil
}
let content = makeContentObject(title: change.pipeline.name)
content.body = "Build started."
if let facts = factsAboutBuild(change.pipeline.status.lastBuild) {
content.body.append("\n\(facts)")
}
if let webUrl = change.pipeline.status.webUrl {
addWebUrl(webUrl, to: content)
}
return content
}

private func notificationContentForFinished(change: StatusChange) -> UNNotificationContent? {
let status = change.pipeline.status
let type = notificationTypeForBuild(status.lastBuild, previousBuild: change.previousStatus.lastBuild)
if !UserDefaults.active.bool(forKey: DefaultsKey.key(forNotification: type)) {
return nil
}
let content = makeContentObject(title: change.pipeline.name)
switch type {
case .wasSuccessful: content.body = "The build was successful."; break
case .wasBroken: content.body = "Recent changes broke the build."; break
case .wasFixed: content.body = "Recent changes fixed the build."; break
case .isStillBroken: content.body = "The build is still broken."; break
default: content.body = "The build finished."; break
}
if let build = status.lastBuild {
if let duration = build.duration, let durationAsString = formattedDurationPrecise(duration) {
content.body.append("\nTime: \(durationAsString)")
}
attachImage(forBuild: build, to: content)
}
if let webUrl = status.webUrl {
addWebUrl(webUrl, to: content)
}
return content
private func shouldSendStartNotification(change: StatusChange) -> Bool {
UserDefaults.active.bool(forKey: DefaultsKey.key(forNotification: .started))
}

private func makeContentObject(title: String) -> UNMutableNotificationContent {
let content = UNMutableNotificationContent()
content.title = "\(title)"
return content
private func addContentForStartedNotification(_ content: UNMutableNotificationContent, change: StatusChange) {
content.title = "Build started"
content.body = change.pipeline.name
if let build = change.pipeline.status.lastBuild, let facts = factsAboutBuild(build) {
content.body.append("\n\(facts)")
}
}

private func factsAboutBuild(_ build: Build?) -> String? {
guard let build = build else {
return nil
}
private func factsAboutBuild(_ build: Build) -> String? {
var facts: String? = nil
if let duration = build.duration {
if let durationAsString = formattedDuration(duration) {
Expand All @@ -101,6 +74,25 @@ class NotificationFactory {
return facts
}

private func shouldSendFinishedNotification(change: StatusChange) -> Bool {
let type = notificationTypeForBuild(change.pipeline.status.lastBuild, previousBuild: change.previousStatus.lastBuild)
return UserDefaults.active.bool(forKey: DefaultsKey.key(forNotification: type))

}

private func addContentForFinishedNotification(_ content: UNMutableNotificationContent, change: StatusChange) {
content.title = "Build finished"
let status = change.pipeline.status
let type = notificationTypeForBuild(status.lastBuild, previousBuild: change.previousStatus.lastBuild)
if let description = desciptionForType(type) {
content.title.append(": \(description)")
}
content.body = change.pipeline.name
// if let build = status.lastBuild {
// attachImage(forBuild: build, to: content)
// }
}

private func notificationTypeForBuild(_ build: Build?, previousBuild previous: Build?) -> NotificationType {
switch build?.result {
case .success:
Expand All @@ -112,6 +104,16 @@ class NotificationFactory {
}
}

private func desciptionForType(_ type: NotificationType) -> String? {
switch type {
case .wasSuccessful: return "success"
case .wasBroken: return "broken"
case .wasFixed: return "fixed"
case .isStillBroken: return "still broken"
default: return nil
}
}

private func attachImage(forBuild build: Build, to content: UNMutableNotificationContent) {
do {
guard let imageUrl = NSImage.urlOfImage(forResult: build.result) else {
Expand All @@ -136,13 +138,4 @@ class NotificationFactory {
return formatter.string(from: duration)
}

private func formattedDurationPrecise(_ duration: TimeInterval) -> String? {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .abbreviated
formatter.collapsesLargestUnit = true
formatter.maximumUnitCount = 2
return formatter.string(from: duration)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class GitHubPipelineBuilder: ObservableObject {
if repository.isValid {
newName.append(repository.name)
if workflow.isValid {
newName.append(String(format: " (%@)", workflow.name))
newName.append(String(format: " | %@", workflow.name))
}
}
self.repository = repository
Expand Down
2 changes: 1 addition & 1 deletion CCMenu/Source/Settings/NotificationSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct NotificationSettings: View {
.padding([ .top, .bottom ], 4)

Toggle(isOn: $notificationSuccessful) {
Text("Build finished: successful")
Text("Build finished: success")
Text("The previous build was successful, and the last build finished sucessfully, too.")
.fixedSize(horizontal: false, vertical: true)
}
Expand Down
40 changes: 20 additions & 20 deletions CCMenuTests/NotificationFactoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class NotificationFactoryTests: XCTestCase {
let notification = factory.notificationContent(change: change)

XCTAssertNotNil(notification)
XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("Build started.", notification?.body)
XCTAssertEqual("Build started", notification?.title)
XCTAssertEqual("connectfour", notification?.body)
}

func testCreatesStartNotificationWithSuccessfulLastBuild() throws {
Expand All @@ -55,8 +55,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("Build started.\nLast build was successful.", notification?.body)
XCTAssertEqual("Build started", notification?.title)
XCTAssertEqual("connectfour\nLast build was successful.", notification?.body)
}

func testCreatesStartNotificationWithSuccessfulLastBuildWithDurationThatNeedsRounding() throws {
Expand All @@ -67,8 +67,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("Build started.\nLast build took 1 minute.", notification?.body)
XCTAssertEqual("Build started", notification?.title)
XCTAssertEqual("connectfour\nLast build took 1 minute.", notification?.body)
}

func testCreatesStartNotificationWithFailedLastBuildWithDurationThatCanBeCollapsed() throws {
Expand All @@ -79,8 +79,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("Build started.\nLast build failed after 62 minutes.", notification?.body)
XCTAssertEqual("Build started", notification?.title)
XCTAssertEqual("connectfour\nLast build failed after 62 minutes.", notification?.body)
}

func testCreatesStartNotificationWithUnknownLastBuildWithDurationThatNeedsHoursAndMinutes() throws {
Expand All @@ -91,8 +91,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("Build started.\nLast build took 2 hours, 5 minutes.", notification?.body)
XCTAssertEqual("Build started", notification?.title)
XCTAssertEqual("connectfour\nLast build took 2 hours, 5 minutes.", notification?.body)
}

func testAddsWebUrlToUserInfoToStartNotification() throws {
Expand Down Expand Up @@ -127,8 +127,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("The build was successful.\nTime: 5m", notification?.body)
XCTAssertEqual("Build finished: success", notification?.title)
XCTAssertEqual("connectfour", notification?.body)
}

func testCreatesCompletionNotificationForSuccessfulBuildFollowingFailedBuild() throws {
Expand All @@ -139,8 +139,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("Recent changes fixed the build.", notification?.body)
XCTAssertEqual("Build finished: fixed", notification?.title)
XCTAssertEqual("connectfour", notification?.body)
}

func testCreatesCompletionNotificationForFailedBuildWithTime() throws {
Expand All @@ -151,8 +151,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("Recent changes broke the build.\nTime: 5m", notification?.body)
XCTAssertEqual("Build finished: broken", notification?.title)
XCTAssertEqual("connectfour", notification?.body)
}

func testCreatesCompletionNotificationForFailedBuildFollowingFailedBuild() throws {
Expand All @@ -163,8 +163,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("The build is still broken.", notification?.body)
XCTAssertEqual("Build finished: still broken", notification?.title)
XCTAssertEqual("connectfour", notification?.body)
}

func testCreatesCompletionNotificationForOtherBuildResult() throws {
Expand All @@ -175,8 +175,8 @@ class NotificationFactoryTests: XCTestCase {

let notification = factory.notificationContent(change: change)

XCTAssertEqual("connectfour", notification?.title)
XCTAssertEqual("The build finished.", notification?.body)
XCTAssertEqual("Build finished", notification?.title)
XCTAssertEqual("connectfour", notification?.body)
}

func testAddsWebUrlToUserInfoToCompletionNotification() throws {
Expand Down

0 comments on commit 87a45da

Please sign in to comment.