Add NSUserActivity's for timelines

This commit is contained in:
Shadowfacts 2019-09-15 20:43:06 -04:00
parent e17e00583f
commit 32d6756762
5 changed files with 121 additions and 3 deletions

View File

@ -41,3 +41,50 @@ extension Timeline {
return request return request
} }
} }
extension Timeline: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(String.self, forKey: .type)
switch type {
case "home":
self = .home
case "public":
self = .public(local: try container.decode(Bool.self, forKey: .local))
case "tag":
self = .tag(hashtag: try container.decode(String.self, forKey: .hashtag))
case "list":
self = .list(id: try container.decode(String.self, forKey: .listID))
case "direct":
self = .direct
default:
throw DecodingError.dataCorruptedError(forKey: CodingKeys.type, in: container, debugDescription: "Timeline type must be one of 'home', 'local', 'tag', 'list', or 'direct'")
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .home:
try container.encode("home", forKey: .type)
case let .public(local):
try container.encode("public", forKey: .type)
try container.encode(local, forKey: .local)
case let .tag(hashtag):
try container.encode("tag", forKey: .type)
try container.encode(hashtag, forKey: .hashtag)
case let .list(id):
try container.encode("list", forKey: .type)
try container.encode(id, forKey: .listID)
case .direct:
try container.encode("direct", forKey: .type)
}
}
enum CodingKeys: String, CodingKey {
case type
case local
case hashtag
case listID
}
}

View File

@ -4,6 +4,7 @@
<dict> <dict>
<key>NSUserActivityTypes</key> <key>NSUserActivityTypes</key>
<array> <array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.show-timeline</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.check-notifications</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.check-notifications</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.new-post</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER).activity.new-post</string>
</array> </array>

View File

@ -44,9 +44,11 @@ class TimelineTableViewController: EnhancedTableViewController {
title = timeline.title title = timeline.title
tabBarItem.image = timeline.tabBarImage tabBarItem.image = timeline.tabBarImage
self.refreshControl = UIRefreshControl() self.refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: #selector(refreshStatuses(_:)), for: .valueChanged) refreshControl!.addTarget(self, action: #selector(refreshStatuses(_:)), for: .valueChanged)
userActivity = UserActivityManager.showTimelineActivity(timeline: timeline)
} }
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {

View File

@ -12,6 +12,9 @@ import Pachyderm
class UserActivityManager { class UserActivityManager {
// MARK: - Utils // MARK: - Utils
private static let encoder = PropertyListEncoder()
private static let decoder = PropertyListDecoder()
private static func present(_ vc: UIViewController, animated: Bool = true) { private static func present(_ vc: UIViewController, animated: Bool = true) {
UIApplication.shared.delegate?.window??.rootViewController?.present(vc, animated: animated) UIApplication.shared.delegate?.window??.rootViewController?.present(vc, animated: animated)
} }
@ -52,4 +55,66 @@ class UserActivityManager {
tabBarController.selectedIndex = 1 tabBarController.selectedIndex = 1
} }
// MARK: - Show Timeline
static func showTimelineActivity(timeline: Timeline) -> NSUserActivity? {
guard let timelineData = try? encoder.encode(timeline) else { return nil }
let activity = NSUserActivity(type: .showTimeline)
activity.isEligibleForPrediction = true
activity.userInfo = ["timelineData": timelineData]
switch timeline {
case .home:
activity.title = NSLocalizedString("Show Home Timeline", comment: "home timeline shortcut title")
activity.suggestedInvocationPhrase = NSLocalizedString("Show my home timeline", comment: "home timeline shortcut invocation phrase")
case .public(local: true):
activity.title = NSLocalizedString("Show Local Timeline", comment: "local timeline shortcut title")
activity.suggestedInvocationPhrase = NSLocalizedString("Show my local timeline", comment: "local timeline shortcut invocation phrase")
case .public(local: false):
activity.title = NSLocalizedString("Show Federated Timeline", comment: "federated timeline shortcut title")
activity.suggestedInvocationPhrase = NSLocalizedString("Show my federated timeline", comment: "federated timeline invocation phrase")
case let .tag(hashtag):
activity.title = String(format: NSLocalizedString("Show #%@", comment: "show hashtag shortcut title"), hashtag)
activity.suggestedInvocationPhrase = String(format: NSLocalizedString("Show the %@ hashtag", comment: "hashtag shortcut invocation phrase"), hashtag)
case .list:
// todo: add title to list
activity.title = NSLocalizedString("Show List", comment: "list timeline shortcut title")
activity.suggestedInvocationPhrase = NSLocalizedString("Show my list", comment: "list timeline invocation phrase")
case .direct:
activity.title = NSLocalizedString("Show Direct Messages", comment: "direct message timeline shortcut title")
activity.suggestedInvocationPhrase = NSLocalizedString("Show my direct messages", comment: "direct message timeline invocation phrase")
}
return activity
}
static func handleShowTimeline(activity: NSUserActivity) {
guard let timelineData = activity.userInfo?["timelineData"] as? Data,
let timeline = try? decoder.decode(Timeline.self, from: timelineData) else {
return
}
let tabBarController = UIApplication.shared.keyWindow!.rootViewController! as! UITabBarController
tabBarController.selectedIndex = 0
let navigationController = tabBarController.viewControllers![0] as! UINavigationController
switch timeline {
case .home, .public(true), .public(false):
navigationController.popToRootViewController(animated: false)
let rootController = navigationController.viewControllers.first! as! SegmentedPageViewController
let index: Int
switch timeline {
case .home:
index = 0
case .public(false):
index = 1
case .public(true):
index = 2
default:
fatalError()
}
rootController.segmentedControl.selectedSegmentIndex = index
rootController.selectPage(at: index, animated: false)
default:
navigationController.pushViewController(TimelineTableViewController(for: timeline), animated: false)
}
}
} }

View File

@ -9,8 +9,9 @@
import Foundation import Foundation
enum UserActivityType: String { enum UserActivityType: String {
case newPost = "net.shadowfacts.tusker.activity.new-post" case newPost = "net.shadowfacts.Tusker.activity.new-post"
case checkNotifications = "net.shadowfacts.tusker.activity.check-notifications" case checkNotifications = "net.shadowfacts.Tusker.activity.check-notifications"
case showTimeline = "net.shadowfacts.Tusker.activity.show-timeline"
} }
extension UserActivityType { extension UserActivityType {
@ -20,6 +21,8 @@ extension UserActivityType {
return UserActivityManager.handleNewPost return UserActivityManager.handleNewPost
case .checkNotifications: case .checkNotifications:
return UserActivityManager.handleCheckNotifications return UserActivityManager.handleCheckNotifications
case .showTimeline:
return UserActivityManager.handleShowTimeline
} }
} }
} }