forked from shadowfacts/Tusker
Add ability to save and view instance public timelines
This commit is contained in:
parent
f92a2acc97
commit
377b5f5c85
|
@ -81,7 +81,7 @@ public class Client {
|
|||
}
|
||||
|
||||
func createURLRequest<Result>(request: Request<Result>) -> URLRequest? {
|
||||
guard var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: true) else { return nil }
|
||||
guard var components = URLComponents(url: request.baseURL ?? baseURL, resolvingAgainstBaseURL: true) else { return nil }
|
||||
components.path = request.path
|
||||
components.queryItems = request.queryParameters.queryItems
|
||||
guard let url = components.url else { return nil }
|
||||
|
|
|
@ -11,6 +11,7 @@ import Foundation
|
|||
public enum Timeline {
|
||||
case home
|
||||
case `public`(local: Bool)
|
||||
case instance(instanceURL: URL)
|
||||
case tag(hashtag: String)
|
||||
case list(id: String)
|
||||
case direct
|
||||
|
@ -21,7 +22,7 @@ extension Timeline {
|
|||
switch self {
|
||||
case .home:
|
||||
return "/api/v1/timelines/home"
|
||||
case .public:
|
||||
case .public, .instance(_):
|
||||
return "/api/v1/timelines/public"
|
||||
case let .tag(hashtag):
|
||||
return "/api/v1/timelines/tag/\(hashtag)"
|
||||
|
@ -33,7 +34,12 @@ extension Timeline {
|
|||
}
|
||||
|
||||
func request(range: RequestRange) -> Request<[Status]> {
|
||||
var request = Request<[Status]>(method: .get, path: endpoint)
|
||||
var request: Request<[Status]>
|
||||
if case let .instance(instanceURL) = self {
|
||||
request = Request<[Status]>(method: .get, baseURL: instanceURL, path: endpoint)
|
||||
} else {
|
||||
request = Request<[Status]>(method: .get, path: endpoint)
|
||||
}
|
||||
if case .public(true) = self {
|
||||
request.queryParameters.append("local" => true)
|
||||
}
|
||||
|
@ -51,6 +57,8 @@ extension Timeline: Codable {
|
|||
self = .home
|
||||
case "public":
|
||||
self = .public(local: try container.decode(Bool.self, forKey: .local))
|
||||
case "instanceURL":
|
||||
self = .instance(instanceURL: try container.decode(URL.self, forKey: .instanceURL))
|
||||
case "tag":
|
||||
self = .tag(hashtag: try container.decode(String.self, forKey: .hashtag))
|
||||
case "list":
|
||||
|
@ -70,6 +78,9 @@ extension Timeline: Codable {
|
|||
case let .public(local):
|
||||
try container.encode("public", forKey: .type)
|
||||
try container.encode(local, forKey: .local)
|
||||
case let .instance(instanceURL):
|
||||
try container.encode("instanceURL", forKey: .type)
|
||||
try container.encode(instanceURL, forKey: .instanceURL)
|
||||
case let .tag(hashtag):
|
||||
try container.encode("tag", forKey: .type)
|
||||
try container.encode(hashtag, forKey: .hashtag)
|
||||
|
@ -84,6 +95,7 @@ extension Timeline: Codable {
|
|||
enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
case local
|
||||
case instanceURL
|
||||
case hashtag
|
||||
case listID
|
||||
}
|
||||
|
|
|
@ -10,12 +10,14 @@ import Foundation
|
|||
|
||||
public struct Request<ResultType: Decodable> {
|
||||
let method: Method
|
||||
let baseURL: URL?
|
||||
let path: String
|
||||
let body: Body
|
||||
var queryParameters: [Parameter]
|
||||
|
||||
init(method: Method, path: String, body: Body = .empty, queryParameters: [Parameter] = []) {
|
||||
init(method: Method, baseURL: URL? = nil, path: String, body: Body = .empty, queryParameters: [Parameter] = []) {
|
||||
self.method = method
|
||||
self.baseURL = baseURL
|
||||
self.path = path
|
||||
self.body = body
|
||||
self.queryParameters = queryParameters
|
||||
|
|
|
@ -167,6 +167,9 @@
|
|||
D6945C2F23AC47C3005C403C /* SavedHashtagsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C2E23AC47C3005C403C /* SavedHashtagsManager.swift */; };
|
||||
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */; };
|
||||
D6945C3423AC6431005C403C /* AddSavedHashtagViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */; };
|
||||
D6945C3623AC6C09005C403C /* SavedInstancesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3523AC6C09005C403C /* SavedInstancesManager.swift */; };
|
||||
D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3723AC739F005C403C /* InstanceTimelineViewController.swift */; };
|
||||
D6945C3A23AC75E2005C403C /* FindInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6945C3923AC75E2005C403C /* FindInstanceViewController.swift */; };
|
||||
D6A3BC7723218E1300FD64D5 /* TimelineSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7323218C6E00FD64D5 /* TimelineSegment.swift */; };
|
||||
D6A3BC7923218E9200FD64D5 /* NotificationGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7823218E9200FD64D5 /* NotificationGroup.swift */; };
|
||||
D6A3BC7C232195C600FD64D5 /* ActionNotificationGroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A3BC7A232195C600FD64D5 /* ActionNotificationGroupTableViewCell.swift */; };
|
||||
|
@ -441,6 +444,9 @@
|
|||
D6945C2E23AC47C3005C403C /* SavedHashtagsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedHashtagsManager.swift; sourceTree = "<group>"; };
|
||||
D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineViewController.swift; sourceTree = "<group>"; };
|
||||
D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSavedHashtagViewController.swift; sourceTree = "<group>"; };
|
||||
D6945C3523AC6C09005C403C /* SavedInstancesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedInstancesManager.swift; sourceTree = "<group>"; };
|
||||
D6945C3723AC739F005C403C /* InstanceTimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceTimelineViewController.swift; sourceTree = "<group>"; };
|
||||
D6945C3923AC75E2005C403C /* FindInstanceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FindInstanceViewController.swift; path = Tusker/Screens/FindInstanceViewController.swift; sourceTree = SOURCE_ROOT; };
|
||||
D6A3BC7323218C6E00FD64D5 /* TimelineSegment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSegment.swift; sourceTree = "<group>"; };
|
||||
D6A3BC7823218E9200FD64D5 /* NotificationGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationGroup.swift; sourceTree = "<group>"; };
|
||||
D6A3BC7A232195C600FD64D5 /* ActionNotificationGroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionNotificationGroupTableViewCell.swift; sourceTree = "<group>"; };
|
||||
|
@ -738,6 +744,7 @@
|
|||
children = (
|
||||
D627943D23A564D400D38C68 /* ExploreViewController.swift */,
|
||||
D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */,
|
||||
D6945C3923AC75E2005C403C /* FindInstanceViewController.swift */,
|
||||
);
|
||||
path = Explore;
|
||||
sourceTree = "<group>";
|
||||
|
@ -788,7 +795,6 @@
|
|||
D641C782213DD7F0004B4513 /* Main */,
|
||||
D641C783213DD7FE004B4513 /* Onboarding */,
|
||||
D641C781213DD7DD004B4513 /* Timeline */,
|
||||
D6945C3023AC4D21005C403C /* Hashtag Timeline */,
|
||||
D641C784213DD819004B4513 /* Profile */,
|
||||
D641C785213DD83B004B4513 /* Conversation */,
|
||||
D641C786213DD852004B4513 /* Notifications */,
|
||||
|
@ -812,6 +818,8 @@
|
|||
children = (
|
||||
D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */,
|
||||
D6F953EB212519E700CF0F2B /* TimelineTableViewController.swift */,
|
||||
D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */,
|
||||
D6945C3723AC739F005C403C /* InstanceTimelineViewController.swift */,
|
||||
);
|
||||
path = Timeline;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1065,14 +1073,6 @@
|
|||
path = de.lproj;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6945C3023AC4D21005C403C /* Hashtag Timeline */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */,
|
||||
);
|
||||
path = "Hashtag Timeline";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6A3BC7223218C6E00FD64D5 /* Utilities */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1226,6 +1226,7 @@
|
|||
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
||||
D627FF75217E923E00CC0648 /* DraftsManager.swift */,
|
||||
D6945C2E23AC47C3005C403C /* SavedHashtagsManager.swift */,
|
||||
D6945C3523AC6C09005C403C /* SavedInstancesManager.swift */,
|
||||
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
||||
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
||||
D6F1F84E2193B9BE00F5FE67 /* Caching */,
|
||||
|
@ -1653,6 +1654,7 @@
|
|||
D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */,
|
||||
0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */,
|
||||
D667E5F52135BCD50057A976 /* ConversationTableViewController.swift in Sources */,
|
||||
D6945C3623AC6C09005C403C /* SavedInstancesManager.swift in Sources */,
|
||||
D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */,
|
||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
|
||||
0411610022B442870030A9B7 /* AttachmentViewController.swift in Sources */,
|
||||
|
@ -1666,6 +1668,7 @@
|
|||
D6028B9B2150811100F223B9 /* MastodonCache.swift in Sources */,
|
||||
D6A3BC802321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift in Sources */,
|
||||
D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */,
|
||||
D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */,
|
||||
D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */,
|
||||
D60D2B8223844C71001B87A3 /* BaseStatusTableViewCell.swift in Sources */,
|
||||
D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */,
|
||||
|
@ -1691,6 +1694,7 @@
|
|||
D6DD353F22F502EC00A9563A /* Preferences+Notification.swift in Sources */,
|
||||
D63661C02381C144004B9E16 /* PreferencesNavigationController.swift in Sources */,
|
||||
D627944A23A6AD6100D38C68 /* BookmarksTableViewController.swift in Sources */,
|
||||
D6945C3A23AC75E2005C403C /* FindInstanceViewController.swift in Sources */,
|
||||
D6AEBB4523216AF800E5038B /* FollowAccountActivity.swift in Sources */,
|
||||
D6538945214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift in Sources */,
|
||||
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */,
|
||||
|
|
|
@ -16,6 +16,8 @@ extension Timeline {
|
|||
return "Home"
|
||||
case let .public(local):
|
||||
return local ? "Local" : "Federated"
|
||||
case let .instance(instance):
|
||||
return instance.host!
|
||||
case let .tag(hashtag):
|
||||
return "#\(hashtag)"
|
||||
case .list:
|
||||
|
@ -35,6 +37,8 @@ extension Timeline {
|
|||
} else {
|
||||
return UIImage(systemName: "globe")
|
||||
}
|
||||
case .instance(_):
|
||||
return UIImage(systemName: "globe")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ class SavedHashtagsManager: Codable {
|
|||
private static var archiveURL = SavedHashtagsManager.documentsDirectory.appendingPathComponent("saved_hashtags").appendingPathExtension("plist")
|
||||
|
||||
static func save() {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
DispatchQueue.global(qos: .utility).async {
|
||||
let encoder = PropertyListEncoder()
|
||||
let data = try? encoder.encode(shared)
|
||||
try? data?.write(to: archiveURL, options: .noFileProtection)
|
||||
|
@ -36,7 +36,7 @@ class SavedHashtagsManager: Codable {
|
|||
|
||||
private var savedHashtags: [Hashtag] = []
|
||||
var sorted: [Hashtag] {
|
||||
return savedHashtags.sorted(by: { $0.name > $1.name })
|
||||
return savedHashtags.sorted(by: { $0.name < $1.name })
|
||||
}
|
||||
|
||||
func isSaved(_ hashtag: Hashtag) -> Bool {
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// SavedInstancesManager.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 12/19/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class SavedInstanceManager: Codable {
|
||||
private(set) static var shared: SavedInstanceManager = load()
|
||||
|
||||
private static var documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
private static var archiveURL = SavedInstanceManager.documentsDirectory.appendingPathComponent("saved_instances").appendingPathExtension("plist")
|
||||
|
||||
static func save() {
|
||||
DispatchQueue.global(qos: .utility).async {
|
||||
let encoder = PropertyListEncoder()
|
||||
let data = try? encoder.encode(shared)
|
||||
try? data?.write(to: archiveURL, options: .noFileProtection)
|
||||
}
|
||||
}
|
||||
|
||||
static func load() -> SavedInstanceManager {
|
||||
let decoder = PropertyListDecoder()
|
||||
if let data = try? Data(contentsOf: archiveURL),
|
||||
let savedInstanceManager = try? decoder.decode(Self.self, from: data) {
|
||||
return savedInstanceManager
|
||||
}
|
||||
return SavedInstanceManager()
|
||||
}
|
||||
|
||||
private init() {}
|
||||
|
||||
private(set) var savedInstances: [URL] = []
|
||||
|
||||
func isSaved(_ url: URL) -> Bool {
|
||||
return savedInstances.contains(url)
|
||||
}
|
||||
|
||||
func add(_ url: URL) {
|
||||
if isSaved(url) {
|
||||
return
|
||||
}
|
||||
savedInstances.append(url)
|
||||
SavedInstanceManager.save()
|
||||
NotificationCenter.default.post(name: .savedInstancesChanged, object: nil)
|
||||
}
|
||||
|
||||
func remove(_ url: URL) {
|
||||
guard isSaved(url) else { return }
|
||||
savedInstances.removeAll(where: { $0 == url })
|
||||
SavedInstanceManager.save()
|
||||
NotificationCenter.default.post(name: .savedInstancesChanged, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension Notification.Name {
|
||||
static let savedInstancesChanged = Notification.Name("savedInstancesChanged")
|
||||
}
|
|
@ -61,6 +61,16 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
cell.imageView!.image = UIImage(systemName: "plus")
|
||||
cell.textLabel!.text = NSLocalizedString("Save Hashtag...", comment: "save hashtag nav item title")
|
||||
cell.accessoryType = .none
|
||||
|
||||
case let .savedInstance(url):
|
||||
cell.imageView!.image = UIImage(systemName: "globe")
|
||||
cell.textLabel!.text = url.host!
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .findInstance:
|
||||
cell.imageView!.image = UIImage(systemName: "magnifyingglass")
|
||||
cell.textLabel!.text = NSLocalizedString("Find An Instance...", comment: "find instance nav item title")
|
||||
cell.accessoryType = .none
|
||||
}
|
||||
|
||||
return cell
|
||||
|
@ -68,10 +78,11 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
dataSource.exploreController = self
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections([.bookmarks, .lists, .savedHashtags])
|
||||
snapshot.appendSections([.bookmarks, .lists, .savedHashtags, .savedInstances])
|
||||
snapshot.appendItems([.bookmarks], toSection: .bookmarks)
|
||||
snapshot.appendItems([.addList], toSection: .lists)
|
||||
snapshot.appendItems(SavedHashtagsManager.shared.sorted.map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||
snapshot.appendItems(SavedInstanceManager.shared.savedInstances.map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
||||
// the initial, static items should not be displayed with an animation
|
||||
UIView.performWithoutAnimation {
|
||||
dataSource.apply(snapshot)
|
||||
|
@ -89,6 +100,7 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
navigationItem.hidesSearchBarWhenScrolling = false
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(savedHashtagsChanged), name: .savedHashtagsChanged, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(savedInstancesChanged), name: .savedInstancesChanged, object: nil)
|
||||
|
||||
reloadLists()
|
||||
}
|
||||
|
@ -117,6 +129,13 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
dataSource.apply(snapshot)
|
||||
}
|
||||
|
||||
@objc func savedInstancesChanged() {
|
||||
var snapshot = dataSource.snapshot()
|
||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedInstances))
|
||||
snapshot.appendItems(SavedInstanceManager.shared.savedInstances.map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
||||
dataSource.apply(snapshot)
|
||||
}
|
||||
|
||||
func deleteList(_ list: List) {
|
||||
let title = String(format: NSLocalizedString("Are you sure want to delete the '%@' list?", comment: "delete list alert title"), list.title)
|
||||
let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
|
||||
|
@ -143,6 +162,10 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
SavedHashtagsManager.shared.remove(hashtag)
|
||||
}
|
||||
|
||||
func removeSavedInstance(_ instanceURL: URL) {
|
||||
SavedInstanceManager.shared.remove(instanceURL)
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
@ -188,6 +211,16 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
let navController = UINavigationController(rootViewController: AddSavedHashtagViewController())
|
||||
present(navController, animated: true)
|
||||
|
||||
case let .savedInstance(url):
|
||||
show(InstanceTimelineViewController(for: url), sender: nil)
|
||||
|
||||
case .findInstance:
|
||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
let findController = FindInstanceViewController()
|
||||
findController.instanceTimelineDelegate = self
|
||||
let navController = UINavigationController(rootViewController: findController)
|
||||
present(navController, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,6 +235,7 @@ extension ExploreViewController {
|
|||
case bookmarks
|
||||
case lists
|
||||
case savedHashtags
|
||||
case savedInstances
|
||||
}
|
||||
enum Item: Hashable {
|
||||
case bookmarks
|
||||
|
@ -209,6 +243,8 @@ extension ExploreViewController {
|
|||
case addList
|
||||
case savedHashtag(Hashtag)
|
||||
case addSavedHashtag
|
||||
case savedInstance(URL)
|
||||
case findInstance
|
||||
|
||||
static func == (lhs: ExploreViewController.Item, rhs: ExploreViewController.Item) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
|
@ -222,6 +258,10 @@ extension ExploreViewController {
|
|||
return a == b
|
||||
case (.addSavedHashtag, .addSavedHashtag):
|
||||
return true
|
||||
case let (.savedInstance(a), .savedInstance(b)):
|
||||
return a == b
|
||||
case (.findInstance, .findInstance):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
@ -240,6 +280,11 @@ extension ExploreViewController {
|
|||
hasher.combine(hashtag.name)
|
||||
case .addSavedHashtag:
|
||||
hasher.combine("addSavedHashtag")
|
||||
case let .savedInstance(url):
|
||||
hasher.combine("savedInstance")
|
||||
hasher.combine(url)
|
||||
case .findInstance:
|
||||
hasher.combine("findInstance")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,6 +299,8 @@ extension ExploreViewController {
|
|||
return NSLocalizedString("Lists", comment: "explore lists section title")
|
||||
case 2:
|
||||
return NSLocalizedString("Saved Hashtags", comment: "explore saved hashtags section title")
|
||||
case 3:
|
||||
return NSLocalizedString("Instance Timelines", comment: "explore instance timelines section title")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
@ -265,6 +312,8 @@ extension ExploreViewController {
|
|||
return true
|
||||
case .savedHashtag(_):
|
||||
return true
|
||||
case .savedInstance(_):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
@ -281,6 +330,8 @@ extension ExploreViewController {
|
|||
exploreController.deleteList(list)
|
||||
case let .savedHashtag(hashtag):
|
||||
exploreController.removeSavedHashtag(hashtag)
|
||||
case let .savedInstance(url):
|
||||
exploreController.removeSavedInstance(url)
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
@ -289,3 +340,15 @@ extension ExploreViewController {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
extension ExploreViewController: InstanceTimelineViewControllerDelegate {
|
||||
func didSaveInstance(url: URL) {
|
||||
dismiss(animated: true) {
|
||||
self.show(InstanceTimelineViewController(for: url), sender: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func didUnsaveInstance(url: URL) {
|
||||
dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// FindInstanceViewController.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 12/19/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FindInstanceViewController: InstanceSelectorTableViewController {
|
||||
|
||||
var instanceTimelineDelegate: InstanceTimelineViewControllerDelegate?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
delegate = self
|
||||
|
||||
searchController.hidesNavigationBarDuringPresentation = false
|
||||
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonPressed))
|
||||
}
|
||||
|
||||
// MARK: - Interaction
|
||||
|
||||
@objc func cancelButtonPressed() {
|
||||
dismiss(animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FindInstanceViewController: InstanceSelectorTableViewControllerDelegate {
|
||||
func didSelectInstance(url: URL) {
|
||||
let instanceTimelineController = InstanceTimelineViewController(for: url)
|
||||
instanceTimelineController.delegate = instanceTimelineDelegate
|
||||
show(instanceTimelineController, sender: self)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// InstanceTimelineViewController.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 12/19/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol InstanceTimelineViewControllerDelegate {
|
||||
func didSaveInstance(url: URL)
|
||||
func didUnsaveInstance(url: URL)
|
||||
}
|
||||
|
||||
class InstanceTimelineViewController: TimelineTableViewController {
|
||||
|
||||
var delegate: InstanceTimelineViewControllerDelegate?
|
||||
|
||||
let instanceURL: URL
|
||||
|
||||
var toggleSaveButton: UIBarButtonItem!
|
||||
var toggleSaveButtonTitle: String {
|
||||
if SavedInstanceManager.shared.isSaved(instanceURL) {
|
||||
return NSLocalizedString("Unsave", comment: "unsave instance button")
|
||||
} else {
|
||||
return NSLocalizedString("Save", comment: "save instance button")
|
||||
}
|
||||
}
|
||||
|
||||
init(for url: URL) {
|
||||
self.instanceURL = url
|
||||
|
||||
super.init(for: .instance(instanceURL: url))
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
toggleSaveButton = UIBarButtonItem(title: toggleSaveButtonTitle, style: .plain, target: self, action: #selector(toggleSaveButtonPressed))
|
||||
navigationItem.rightBarButtonItem = toggleSaveButton
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(savedInstancesChanged), name: .savedInstancesChanged, object: nil)
|
||||
}
|
||||
|
||||
@objc func savedInstancesChanged() {
|
||||
toggleSaveButton.title = toggleSaveButtonTitle
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
// no-op, we don't currently support viewing whole conversations from other instances
|
||||
}
|
||||
|
||||
// MARK: - Interaction
|
||||
@objc func toggleSaveButtonPressed() {
|
||||
if SavedInstanceManager.shared.isSaved(instanceURL) {
|
||||
SavedInstanceManager.shared.remove(instanceURL)
|
||||
delegate?.didUnsaveInstance(url: instanceURL)
|
||||
} else {
|
||||
SavedInstanceManager.shared.add(instanceURL)
|
||||
delegate?.didSaveInstance(url: instanceURL)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -100,6 +100,9 @@ class UserActivityManager {
|
|||
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 .instance(instance):
|
||||
activity.title = String(format: NSLocalizedString("Show %@", comment: "show instance timeline shortcut title"), instance.host!)
|
||||
activity.suggestedInvocationPhrase = String(format: NSLocalizedString("Show the instance %@", comment: "instance timeline shortcut invocation phrase"), instance.host!)
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue