Add notification deep linking for iOS
This commit is contained in:
parent
046ec7de51
commit
0c9a1ba8d0
@ -42,6 +42,7 @@
|
||||
51E490362288C37100C791F0 /* FeedbinDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E490352288C37100C791F0 /* FeedbinDate.swift */; };
|
||||
51E59599228C77BC00FCC42B /* FeedbinUnreadEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E59598228C77BC00FCC42B /* FeedbinUnreadEntry.swift */; };
|
||||
51E5959B228C781500FCC42B /* FeedbinStarredEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */; };
|
||||
51FE1008234635A20056195D /* DeepLinkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51FE1007234635A20056195D /* DeepLinkProvider.swift */; };
|
||||
552032F8229D5D5A009559E0 /* ReaderAPIEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552032ED229D5D5A009559E0 /* ReaderAPIEntry.swift */; };
|
||||
552032F9229D5D5A009559E0 /* ReaderAPISubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552032EE229D5D5A009559E0 /* ReaderAPISubscription.swift */; };
|
||||
552032FB229D5D5A009559E0 /* ReaderAPITag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 552032F0229D5D5A009559E0 /* ReaderAPITag.swift */; };
|
||||
@ -195,6 +196,7 @@
|
||||
51E490352288C37100C791F0 /* FeedbinDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinDate.swift; sourceTree = "<group>"; };
|
||||
51E59598228C77BC00FCC42B /* FeedbinUnreadEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinUnreadEntry.swift; sourceTree = "<group>"; };
|
||||
51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinStarredEntry.swift; sourceTree = "<group>"; };
|
||||
51FE1007234635A20056195D /* DeepLinkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkProvider.swift; sourceTree = "<group>"; };
|
||||
552032ED229D5D5A009559E0 /* ReaderAPIEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderAPIEntry.swift; sourceTree = "<group>"; };
|
||||
552032EE229D5D5A009559E0 /* ReaderAPISubscription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderAPISubscription.swift; sourceTree = "<group>"; };
|
||||
552032F0229D5D5A009559E0 /* ReaderAPITag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderAPITag.swift; sourceTree = "<group>"; };
|
||||
@ -431,6 +433,7 @@
|
||||
510BD112232C3E9D002692E4 /* FeedMetadataFile.swift */,
|
||||
841974001F6DD1EC006346C4 /* Folder.swift */,
|
||||
844B297E210CE37E004020B3 /* UnreadCountProvider.swift */,
|
||||
51FE1007234635A20056195D /* DeepLinkProvider.swift */,
|
||||
5165D71F22835E9800D9D53D /* FeedFinder */,
|
||||
515E4EB12324FF7D0057B0E7 /* Credentials */,
|
||||
8419742B1F6DDE84006346C4 /* LocalAccount */,
|
||||
@ -807,6 +810,7 @@
|
||||
51BB7B84233531BC008E8144 /* AccountBehaviors.swift in Sources */,
|
||||
9E1773D923458D590056A5A8 /* FeedlyResourceId.swift in Sources */,
|
||||
552032FC229D5D5A009559E0 /* ReaderAPIUnreadEntry.swift in Sources */,
|
||||
51FE1008234635A20056195D /* DeepLinkProvider.swift in Sources */,
|
||||
9EC688EA232B973C00A8D0A2 /* FeedlyAPICaller.swift in Sources */,
|
||||
9E1773D32345700F0056A5A8 /* FeedlyLink.swift in Sources */,
|
||||
9EAEC62823331C350085D7C9 /* FeedlyCategory.swift in Sources */,
|
||||
|
21
Frameworks/Account/DeepLinkProvider.swift
Normal file
21
Frameworks/Account/DeepLinkProvider.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// DeepLinkProvider.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Maurice Parker on 10/3/19.
|
||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum DeepLinkKey: String {
|
||||
case accountID = "accountID"
|
||||
case accountName = "accountName"
|
||||
case feedID = "feedID"
|
||||
case articleID = "articleID"
|
||||
case folderName = "folderName"
|
||||
}
|
||||
|
||||
public protocol DeepLinkProvider {
|
||||
var deepLinkUserInfo: [AnyHashable : Any] { get }
|
||||
}
|
@ -11,7 +11,7 @@ import RSCore
|
||||
import RSWeb
|
||||
import Articles
|
||||
|
||||
public final class Feed: DisplayNameProvider, Renamable, UnreadCountProvider, Hashable {
|
||||
public final class Feed: DisplayNameProvider, Renamable, UnreadCountProvider, DeepLinkProvider, Hashable {
|
||||
|
||||
public weak var account: Account?
|
||||
public let url: String
|
||||
@ -179,6 +179,15 @@ public final class Feed: DisplayNameProvider, Renamable, UnreadCountProvider, Ha
|
||||
account.renameFeed(self, to: newName, completion: completion)
|
||||
}
|
||||
|
||||
// MARK: - PathIDUserInfoProvider
|
||||
public var deepLinkUserInfo: [AnyHashable : Any] {
|
||||
return [
|
||||
DeepLinkKey.accountID.rawValue: account?.accountID ?? "",
|
||||
DeepLinkKey.accountName.rawValue: account?.name ?? "",
|
||||
DeepLinkKey.feedID.rawValue: feedID
|
||||
]
|
||||
}
|
||||
|
||||
// MARK: - UnreadCountProvider
|
||||
|
||||
public var unreadCount: Int {
|
||||
|
@ -10,7 +10,7 @@ import Foundation
|
||||
import Articles
|
||||
import RSCore
|
||||
|
||||
public final class Folder: DisplayNameProvider, Renamable, Container, UnreadCountProvider, Hashable {
|
||||
public final class Folder: DisplayNameProvider, Renamable, Container, UnreadCountProvider, DeepLinkProvider, Hashable {
|
||||
|
||||
public weak var account: Account?
|
||||
public var topLevelFeeds: Set<Feed> = Set<Feed>()
|
||||
@ -32,6 +32,15 @@ public final class Folder: DisplayNameProvider, Renamable, Container, UnreadCoun
|
||||
public var nameForDisplay: String {
|
||||
return name ?? Folder.untitledName
|
||||
}
|
||||
|
||||
// MARK: - PathIDUserInfoProvider
|
||||
public var deepLinkUserInfo: [AnyHashable : Any] {
|
||||
return [
|
||||
DeepLinkKey.accountID.rawValue: account?.accountID ?? "",
|
||||
DeepLinkKey.accountName.rawValue: account?.name ?? "",
|
||||
DeepLinkKey.folderName.rawValue: nameForDisplay
|
||||
]
|
||||
}
|
||||
|
||||
// MARK: - UnreadCountProvider
|
||||
|
||||
|
@ -94,7 +94,6 @@
|
||||
5183CCE9226F68D90010922C /* AccountRefreshTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */; };
|
||||
51934CCB230F599B006127BE /* ThemedNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CC1230F5963006127BE /* ThemedNavigationController.swift */; };
|
||||
51934CCE2310792F006127BE /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; };
|
||||
51934CD023108953006127BE /* ActivityID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCF23108953006127BE /* ActivityID.swift */; };
|
||||
51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
||||
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
|
||||
519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; };
|
||||
@ -836,7 +835,6 @@
|
||||
5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountRefreshTimer.swift; sourceTree = "<group>"; };
|
||||
51934CC1230F5963006127BE /* ThemedNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemedNavigationController.swift; sourceTree = "<group>"; };
|
||||
51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = "<group>"; };
|
||||
51934CCF23108953006127BE /* ActivityID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityID.swift; sourceTree = "<group>"; };
|
||||
51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = "<group>"; };
|
||||
5194B5ED22B6965300144881 /* SettingsSubscriptionsImportDocumentPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsImportDocumentPickerView.swift; sourceTree = "<group>"; };
|
||||
5194B5F122B69FCC00144881 /* SettingsSubscriptionsExportDocumentPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionsExportDocumentPickerView.swift; sourceTree = "<group>"; };
|
||||
@ -1301,7 +1299,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
51934CCD2310792F006127BE /* ActivityManager.swift */,
|
||||
51934CCF23108953006127BE /* ActivityID.swift */,
|
||||
51D87EE02311D34700E63F03 /* ActivityType.swift */,
|
||||
);
|
||||
path = Activity;
|
||||
@ -2895,7 +2892,6 @@
|
||||
51CC9B3E231720B2000E842F /* MasterFeedDataSource.swift in Sources */,
|
||||
51C452A322650A1E00C03939 /* HTMLMetadataDownloader.swift in Sources */,
|
||||
51C4528D2265095F00C03939 /* AddFolderViewController.swift in Sources */,
|
||||
51934CD023108953006127BE /* ActivityID.swift in Sources */,
|
||||
51C452782265091600C03939 /* MasterTimelineCellData.swift in Sources */,
|
||||
5148F4552336DB7000F8CD8B /* MasterTimelineTitleView.swift in Sources */,
|
||||
513228FC233037630033D4ED /* Reachability.swift in Sources */,
|
||||
|
@ -1,17 +0,0 @@
|
||||
//
|
||||
// ActivityID.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 8/23/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ActivityID: String {
|
||||
case accountID = "accountID"
|
||||
case accountName = "accountName"
|
||||
case feedID = "feedID"
|
||||
case articleID = "articleID"
|
||||
case folderName = "folderName"
|
||||
}
|
@ -67,12 +67,7 @@ class ActivityManager {
|
||||
let title = NSString.localizedStringWithFormat(localizedText as NSString, folder.nameForDisplay) as String
|
||||
selectingActivity = makeSelectingActivity(type: ActivityType.selectFolder, title: title, identifier: ActivityManager.identifer(for: folder))
|
||||
|
||||
selectingActivity!.userInfo = [
|
||||
ActivityID.accountID.rawValue: folder.account?.accountID ?? "",
|
||||
ActivityID.accountName.rawValue: folder.account?.name ?? "",
|
||||
ActivityID.folderName.rawValue: folder.nameForDisplay
|
||||
]
|
||||
|
||||
selectingActivity!.userInfo = folder.deepLinkUserInfo
|
||||
selectingActivity!.becomeCurrent()
|
||||
}
|
||||
|
||||
@ -83,13 +78,8 @@ class ActivityManager {
|
||||
let title = NSString.localizedStringWithFormat(localizedText as NSString, feed.nameForDisplay) as String
|
||||
selectingActivity = makeSelectingActivity(type: ActivityType.selectFeed, title: title, identifier: ActivityManager.identifer(for: feed))
|
||||
|
||||
selectingActivity!.userInfo = [
|
||||
ActivityID.accountID.rawValue: feed.account?.accountID ?? "",
|
||||
ActivityID.accountName.rawValue: feed.account?.name ?? "",
|
||||
ActivityID.feedID.rawValue: feed.feedID
|
||||
]
|
||||
selectingActivity!.userInfo = feed.deepLinkUserInfo
|
||||
updateSelectingActivityFeedSearchAttributes(with: feed)
|
||||
|
||||
selectingActivity!.becomeCurrent()
|
||||
}
|
||||
|
||||
@ -155,7 +145,7 @@ class ActivityManager {
|
||||
}
|
||||
|
||||
@objc func feedIconDidBecomeAvailable(_ note: Notification) {
|
||||
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed, let activityFeedId = selectingActivity?.userInfo?[ActivityID.feedID.rawValue] as? String else {
|
||||
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed, let activityFeedId = selectingActivity?.userInfo?[DeepLinkKey.feedID.rawValue] as? String else {
|
||||
return
|
||||
}
|
||||
if activityFeedId == feed.feedID {
|
||||
@ -190,12 +180,7 @@ private extension ActivityManager {
|
||||
let keywords = feedNameKeywords + articleTitleKeywords
|
||||
activity.keywords = Set(keywords)
|
||||
|
||||
activity.userInfo = [
|
||||
ActivityID.accountID.rawValue: article.accountID,
|
||||
ActivityID.accountName.rawValue: article.account?.name ?? "",
|
||||
ActivityID.feedID.rawValue: article.feedID,
|
||||
ActivityID.articleID.rawValue: article.articleID
|
||||
]
|
||||
activity.userInfo = article.deepLinkUserInfo
|
||||
activity.isEligibleForSearch = true
|
||||
activity.isEligibleForPrediction = false
|
||||
activity.isEligibleForHandoff = true
|
||||
|
@ -91,6 +91,21 @@ extension Article {
|
||||
|
||||
}
|
||||
|
||||
// MARK: PathIDUserInfoProvider
|
||||
|
||||
extension Article: DeepLinkProvider {
|
||||
|
||||
public var deepLinkUserInfo: [AnyHashable : Any] {
|
||||
return [
|
||||
DeepLinkKey.accountID.rawValue: accountID,
|
||||
DeepLinkKey.accountName.rawValue: account?.name ?? "",
|
||||
DeepLinkKey.feedID.rawValue: feedID,
|
||||
DeepLinkKey.articleID.rawValue: articleID
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: SortableArticle
|
||||
|
||||
extension Article: SortableArticle {
|
||||
|
@ -36,11 +36,16 @@ private extension UserNotificationManager {
|
||||
|
||||
private func sendNotification(feed: Feed, article: Article) {
|
||||
let content = UNMutableNotificationContent()
|
||||
|
||||
|
||||
content.title = feed.nameForDisplay
|
||||
content.body = article.title ?? article.summary ?? ""
|
||||
content.body = TimelineStringFormatter.truncatedTitle(article)
|
||||
if content.body.isEmpty {
|
||||
content.body = TimelineStringFormatter.truncatedSummary(article)
|
||||
}
|
||||
|
||||
content.sound = UNNotificationSound.default
|
||||
|
||||
content.userInfo = article.deepLinkUserInfo
|
||||
|
||||
let request = UNNotificationRequest.init(identifier: "articleID:\(article.articleID)", content: content, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(request)
|
||||
}
|
||||
|
@ -178,6 +178,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
completionHandler([.alert, .badge, .sound])
|
||||
}
|
||||
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
|
||||
defer { completionHandler() }
|
||||
|
||||
if let sceneDelegate = response.targetScene?.delegate as? SceneDelegate {
|
||||
sceneDelegate.handle(response)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: App Initialization
|
||||
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
import SwiftUI
|
||||
import Account
|
||||
import Articles
|
||||
@ -315,16 +316,21 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
case .selectStarred:
|
||||
handleSelectStarred()
|
||||
case .selectFolder:
|
||||
handleSelectFolder(activity)
|
||||
handleSelectFolder(activity.userInfo)
|
||||
case .selectFeed:
|
||||
handleSelectFeed(activity)
|
||||
handleSelectFeed(activity.userInfo)
|
||||
case .nextUnread:
|
||||
selectFirstUnreadInAllUnread()
|
||||
case .readArticle:
|
||||
handleReadArticle(activity)
|
||||
handleReadArticle(activity.userInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func handle(_ response: UNNotificationResponse) {
|
||||
let userInfo = response.notification.request.content.userInfo
|
||||
handleReadArticle(userInfo)
|
||||
}
|
||||
|
||||
func configureThreePanelMode(for size: CGSize) {
|
||||
guard rootSplitViewController.traitCollection.userInterfaceIdiom == .pad && !rootSplitViewController.isCollapsed else {
|
||||
return
|
||||
@ -1606,8 +1612,8 @@ private extension SceneCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func handleSelectFolder(_ activity: NSUserActivity) {
|
||||
guard let accountNode = findAccountNode(for: activity), let folderNode = findFolderNode(for: activity, beginningAt: accountNode) else {
|
||||
func handleSelectFolder(_ userInfo: [AnyHashable : Any]?) {
|
||||
guard let accountNode = findAccountNode(userInfo), let folderNode = findFolderNode(userInfo, beginningAt: accountNode) else {
|
||||
return
|
||||
}
|
||||
if let indexPath = indexPathFor(folderNode) {
|
||||
@ -1615,8 +1621,8 @@ private extension SceneCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func handleSelectFeed(_ activity: NSUserActivity) {
|
||||
guard let accountNode = findAccountNode(for: activity), let feedNode = findFeedNode(for: activity, beginningAt: accountNode) else {
|
||||
func handleSelectFeed(_ userInfo: [AnyHashable : Any]?) {
|
||||
guard let accountNode = findAccountNode(userInfo), let feedNode = findFeedNode(userInfo, beginningAt: accountNode) else {
|
||||
return
|
||||
}
|
||||
if let feed = feedNode.representedObject as? Feed {
|
||||
@ -1624,14 +1630,14 @@ private extension SceneCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func handleReadArticle(_ activity: NSUserActivity) {
|
||||
guard let accountNode = findAccountNode(for: activity), let feedNode = findFeedNode(for: activity, beginningAt: accountNode) else {
|
||||
func handleReadArticle(_ userInfo: [AnyHashable : Any]?) {
|
||||
guard let accountNode = findAccountNode(userInfo), let feedNode = findFeedNode(userInfo, beginningAt: accountNode) else {
|
||||
return
|
||||
}
|
||||
|
||||
discloseFeed(feedNode.representedObject as! Feed) {
|
||||
|
||||
guard let articleID = activity.userInfo?[ActivityID.articleID.rawValue] as? String else { return }
|
||||
guard let articleID = userInfo?[DeepLinkKey.articleID.rawValue] as? String else { return }
|
||||
if let article = self.articles.first(where: { $0.articleID == articleID }) {
|
||||
self.selectArticle(article)
|
||||
}
|
||||
@ -1639,8 +1645,8 @@ private extension SceneCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func findAccountNode(for activity: NSUserActivity) -> Node? {
|
||||
guard let accountID = activity.userInfo?[ActivityID.accountID.rawValue] as? String else {
|
||||
func findAccountNode(_ userInfo: [AnyHashable : Any]?) -> Node? {
|
||||
guard let accountID = userInfo?[DeepLinkKey.accountID.rawValue] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1648,7 +1654,7 @@ private extension SceneCoordinator {
|
||||
return node
|
||||
}
|
||||
|
||||
guard let accountName = activity.userInfo?[ActivityID.accountName.rawValue] as? String else {
|
||||
guard let accountName = userInfo?[DeepLinkKey.accountName.rawValue] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1659,8 +1665,8 @@ private extension SceneCoordinator {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findFolderNode(for activity: NSUserActivity, beginningAt startingNode: Node) -> Node? {
|
||||
guard let folderName = activity.userInfo?[ActivityID.folderName.rawValue] as? String else {
|
||||
func findFolderNode(_ userInfo: [AnyHashable : Any]?, beginningAt startingNode: Node) -> Node? {
|
||||
guard let folderName = userInfo?[DeepLinkKey.folderName.rawValue] as? String else {
|
||||
return nil
|
||||
}
|
||||
if let node = startingNode.descendantNode(where: { ($0.representedObject as? Folder)?.nameForDisplay == folderName }) {
|
||||
@ -1669,8 +1675,8 @@ private extension SceneCoordinator {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findFeedNode(for activity: NSUserActivity, beginningAt startingNode: Node) -> Node? {
|
||||
guard let feedID = activity.userInfo?[ActivityID.feedID.rawValue] as? String else {
|
||||
func findFeedNode(_ userInfo: [AnyHashable : Any]?, beginningAt startingNode: Node) -> Node? {
|
||||
guard let feedID = userInfo?[DeepLinkKey.feedID.rawValue] as? String else {
|
||||
return nil
|
||||
}
|
||||
if let node = startingNode.descendantNode(where: { ($0.representedObject as? Feed)?.feedID == feedID }) {
|
||||
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
import Account
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
@ -28,8 +29,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
if let notificationResponse = connectionOptions.notificationResponse {
|
||||
window!.makeKeyAndVisible()
|
||||
coordinator.handle(notificationResponse)
|
||||
return
|
||||
}
|
||||
|
||||
if let userActivity = connectionOptions.userActivities.first ?? session.stateRestorationActivity {
|
||||
self.coordinator.handle(userActivity)
|
||||
coordinator.handle(userActivity)
|
||||
}
|
||||
|
||||
window!.makeKeyAndVisible()
|
||||
@ -55,6 +62,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? {
|
||||
return coordinator.stateRestorationActivity
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
func handle(_ response: UNNotificationResponse) {
|
||||
coordinator.handle(response)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user