forked from expo/expo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[expo-notifications][iOS] Swift conversion 3: Scheduling, Notificatio…
…nBuilder, NotificationCenterDelegate, Presentation (expo#33253) # Why Migrate scheduler, notification builder, and presentation module to Swift # How - Rewrite scheduler module in Swift - Rewrite presentation module in Swift - Create singleton to receive notification center events and allow modules to register as delegates for those events - Replace Objective C dictionary categories with a Swift implementation using Records # Test Plan - CI should pass, including SwiftLint checks Behavior of notification test app on real device should not change # Checklist - [x] Documentation is up to date to reflect these changes (eg: https://docs.expo.dev and README.md). - [x] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) - [x] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin).
- Loading branch information
1 parent
3059147
commit a729e1a
Showing
18 changed files
with
699 additions
and
660 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 0 additions & 19 deletions
19
packages/expo-notifications/ios/EXNotifications/Building/EXNotificationBuilder.h
This file was deleted.
Oops, something went wrong.
105 changes: 0 additions & 105 deletions
105
packages/expo-notifications/ios/EXNotifications/Building/EXNotificationBuilder.m
This file was deleted.
Oops, something went wrong.
147 changes: 147 additions & 0 deletions
147
packages/expo-notifications/ios/EXNotifications/Building/NotificationBuilder.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// Copyright © 2024 650 Industries. All rights reserved. | ||
|
||
import ExpoModulesCore | ||
|
||
struct NotificationRequestRecord: Record { | ||
@Field | ||
var title: String? | ||
@Field | ||
var subtitle: String? | ||
@Field | ||
var body: String? | ||
@Field | ||
var launchImageName: String? | ||
@Field | ||
var badge: Int? | ||
@Field | ||
var userInfo: [String: Any]? | ||
@Field | ||
var categoryIdentifier: String? | ||
@Field | ||
var sound: Either<Bool, String>? | ||
@Field | ||
var attachments: [[String: Any]]? | ||
@Field | ||
var interruptionLevel: String? | ||
} | ||
|
||
public class NotificationBuilder: NSObject { | ||
public class func content(_ request: [String: Any], appContext: AppContext) throws -> UNMutableNotificationContent { | ||
let content = UNMutableNotificationContent() | ||
let request = try NotificationRequestRecord(from: request, appContext: appContext) | ||
|
||
if let title = request.title { | ||
content.title = title | ||
} | ||
|
||
if let subtitle = request.subtitle { | ||
content.subtitle = subtitle | ||
} | ||
|
||
if let body = request.body { | ||
content.body = body | ||
} | ||
|
||
if let launchImageName = request.launchImageName { | ||
content.launchImageName = launchImageName | ||
} | ||
|
||
if let badge = request.badge { | ||
// swiftlint:disable:next legacy_objc_type | ||
content.badge = NSNumber.init(value: badge) | ||
} | ||
|
||
if let userInfo = request.userInfo { | ||
content.userInfo = userInfo | ||
} | ||
|
||
if let categoryIdentifier = request.categoryIdentifier { | ||
content.categoryIdentifier = categoryIdentifier | ||
} | ||
|
||
if let sound = request.sound { | ||
if let soundBool = try? sound.as(Bool.self) { | ||
content.sound = soundBool ? .default : .none | ||
} else if let soundName = try? sound.as(String.self) { | ||
if soundName == "default" { | ||
content.sound = UNNotificationSound.default | ||
} else if soundName == "defaultCritical" { | ||
content.sound = UNNotificationSound.defaultCritical | ||
} else { | ||
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName)) | ||
} | ||
} | ||
} | ||
|
||
var attachments: [UNNotificationAttachment] = [] | ||
if let attachmentsArray = request.attachments { | ||
for attachmentObject in attachmentsArray { | ||
if let attachment: UNNotificationAttachment = attachment(attachmentObject) { | ||
attachments.append(attachment) | ||
} | ||
} | ||
} | ||
content.attachments = attachments | ||
if let interruptionLevel = request.interruptionLevel { | ||
content.interruptionLevel = deserializeInterruptionLevel(interruptionLevel) | ||
} | ||
|
||
return content | ||
} | ||
|
||
class func attachment(_ request: [String: Any]) -> UNNotificationAttachment? { | ||
let identifier = request["identifier"] as? String ?? "" | ||
let uri = request["uri"] as? String ?? "" | ||
do { | ||
if let url = URL(string: uri), | ||
let attachment: UNNotificationAttachment = | ||
try? UNNotificationAttachment( | ||
identifier: identifier, | ||
url: url, | ||
options: attachmentOptions(request) | ||
) { | ||
return attachment | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
class func attachmentOptions(_ request: [String: Any]) -> [String: Any] { | ||
var options: [String: Any] = [:] | ||
if let typeHint = request["typeHint"] as? String { | ||
options[UNNotificationAttachmentOptionsTypeHintKey] = typeHint | ||
} | ||
if let hideThumbnail = request["hideThumbnail"] as? Bool { | ||
options[UNNotificationAttachmentOptionsThumbnailHiddenKey] = hideThumbnail | ||
} | ||
if let thumbnailClipArea = request["thumbnailClipArea"] as? [String: Any] { | ||
let x = thumbnailClipArea["x"] as? Double | ||
let y = thumbnailClipArea["y"] as? Double | ||
let width = thumbnailClipArea["width"] as? Double | ||
let height = thumbnailClipArea["height"] as? Double | ||
if let x, let y, let width, let height { | ||
options[UNNotificationAttachmentOptionsThumbnailClippingRectKey] = | ||
CGRect( | ||
x: x, | ||
y: y, | ||
width: width, | ||
height: height | ||
) | ||
} | ||
} | ||
if let thumbnailTime = request["thumbnailTime"] as? TimeInterval { | ||
options[UNNotificationAttachmentOptionsThumbnailTimeKey] = thumbnailTime | ||
} | ||
return options | ||
} | ||
|
||
class func deserializeInterruptionLevel(_ interruptionLevel: String) -> UNNotificationInterruptionLevel { | ||
switch interruptionLevel { | ||
case "passive": return .passive | ||
case "active": return .active | ||
case "timeSensitive": return .timeSensitive | ||
case "critical": return .critical | ||
default: return .passive | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 0 additions & 7 deletions
7
...ifications/ios/EXNotifications/Notifications/NSDictionary+EXNotificationsVerifyingClass.h
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.