forked from shadowfacts/Tusker
parent
6831ab5385
commit
ae6a0513e4
|
@ -8,7 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public class Hashtag: Decodable {
|
||||
public class Hashtag: Codable {
|
||||
public let name: String
|
||||
public let url: URL
|
||||
public let history: [History]?
|
||||
|
@ -27,7 +27,7 @@ public class Hashtag: Decodable {
|
|||
}
|
||||
|
||||
extension Hashtag {
|
||||
public class History: Decodable {
|
||||
public class History: Codable {
|
||||
public let day: Date
|
||||
public let uses: Int
|
||||
public let accounts: Int
|
||||
|
@ -42,7 +42,7 @@ extension Hashtag {
|
|||
|
||||
extension Hashtag: Equatable, Hashable {
|
||||
public static func ==(lhs: Hashtag, rhs: Hashtag) -> Bool {
|
||||
return lhs.url == rhs.url
|
||||
return lhs.name == rhs.name
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
|
|
|
@ -164,6 +164,9 @@
|
|||
D68632AB21ED8319008C716E /* GMImagePickerController.h in Headers */ = {isa = PBXBuildFile; fileRef = D686329121ED8319008C716E /* GMImagePickerController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D68632AC21ED8319008C716E /* GMImagePicker.strings in Resources */ = {isa = PBXBuildFile; fileRef = D686329321ED8319008C716E /* GMImagePicker.strings */; };
|
||||
D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68FEC4E232C5BC300C84F23 /* SegmentedPageViewController.swift */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
|
@ -435,6 +438,9 @@
|
|||
D686329121ED8319008C716E /* GMImagePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GMImagePickerController.h; sourceTree = "<group>"; };
|
||||
D686329421ED8319008C716E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = GMImagePicker.strings; sourceTree = "<group>"; };
|
||||
D68FEC4E232C5BC300C84F23 /* SegmentedPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedPageViewController.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -731,6 +737,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D627943D23A564D400D38C68 /* ExploreViewController.swift */,
|
||||
D6945C3323AC6431005C403C /* AddSavedHashtagViewController.swift */,
|
||||
);
|
||||
path = Explore;
|
||||
sourceTree = "<group>";
|
||||
|
@ -781,6 +788,7 @@
|
|||
D641C782213DD7F0004B4513 /* Main */,
|
||||
D641C783213DD7FE004B4513 /* Onboarding */,
|
||||
D641C781213DD7DD004B4513 /* Timeline */,
|
||||
D6945C3023AC4D21005C403C /* Hashtag Timeline */,
|
||||
D641C784213DD819004B4513 /* Profile */,
|
||||
D641C785213DD83B004B4513 /* Conversation */,
|
||||
D641C786213DD852004B4513 /* Notifications */,
|
||||
|
@ -1057,6 +1065,14 @@
|
|||
path = de.lproj;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6945C3023AC4D21005C403C /* Hashtag Timeline */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D6945C3123AC4D36005C403C /* HashtagTimelineViewController.swift */,
|
||||
);
|
||||
path = "Hashtag Timeline";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6A3BC7223218C6E00FD64D5 /* Utilities */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1209,6 +1225,7 @@
|
|||
D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */,
|
||||
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
||||
D627FF75217E923E00CC0648 /* DraftsManager.swift */,
|
||||
D6945C2E23AC47C3005C403C /* SavedHashtagsManager.swift */,
|
||||
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
||||
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
||||
D6F1F84E2193B9BE00F5FE67 /* Caching */,
|
||||
|
@ -1641,6 +1658,7 @@
|
|||
0411610022B442870030A9B7 /* AttachmentViewController.swift in Sources */,
|
||||
D611C2CF232DC61100C86A49 /* HashtagTableViewCell.swift in Sources */,
|
||||
D627944F23A9C99800D38C68 /* EditListAccountsViewController.swift in Sources */,
|
||||
D6945C3423AC6431005C403C /* AddSavedHashtagViewController.swift in Sources */,
|
||||
D627943723A552C200D38C68 /* BookmarkStatusActivity.swift in Sources */,
|
||||
D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */,
|
||||
D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */,
|
||||
|
@ -1680,6 +1698,7 @@
|
|||
0427033822B30F5F000D31B6 /* BehaviorPrefsView.swift in Sources */,
|
||||
D627943923A553B600D38C68 /* UnbookmarkStatusActivity.swift in Sources */,
|
||||
D64D0AAD2128D88B005A6F37 /* LocalData.swift in Sources */,
|
||||
D6945C2F23AC47C3005C403C /* SavedHashtagsManager.swift in Sources */,
|
||||
D6C94D892139E6EC00CB5196 /* AttachmentView.swift in Sources */,
|
||||
D6C693EF216192C2007D6A6D /* TuskerNavigationDelegate.swift in Sources */,
|
||||
D6C94D872139E62700CB5196 /* LargeImageViewController.swift in Sources */,
|
||||
|
@ -1703,6 +1722,7 @@
|
|||
D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */,
|
||||
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */,
|
||||
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */,
|
||||
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
||||
D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */,
|
||||
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */,
|
||||
D646C95A213B5D0500269FB5 /* LargeImageInteractionController.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// SavedHashtagsManager.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 12/19/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Pachyderm
|
||||
|
||||
class SavedHashtagsManager: Codable {
|
||||
private(set) static var shared: SavedHashtagsManager = load()
|
||||
|
||||
private static var documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
||||
private static var archiveURL = SavedHashtagsManager.documentsDirectory.appendingPathComponent("saved_hashtags").appendingPathExtension("plist")
|
||||
|
||||
static func save() {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
let encoder = PropertyListEncoder()
|
||||
let data = try? encoder.encode(shared)
|
||||
try? data?.write(to: archiveURL, options: .noFileProtection)
|
||||
}
|
||||
}
|
||||
|
||||
static func load() -> SavedHashtagsManager {
|
||||
let decoder = PropertyListDecoder()
|
||||
if let data = try? Data(contentsOf: archiveURL),
|
||||
let savedHashtagsManager = try? decoder.decode(Self.self, from: data) {
|
||||
return savedHashtagsManager
|
||||
}
|
||||
return SavedHashtagsManager()
|
||||
}
|
||||
|
||||
private init() {}
|
||||
|
||||
private var savedHashtags: [Hashtag] = []
|
||||
var sorted: [Hashtag] {
|
||||
return savedHashtags.sorted(by: { $0.name > $1.name })
|
||||
}
|
||||
|
||||
func isSaved(_ hashtag: Hashtag) -> Bool {
|
||||
return savedHashtags.contains(hashtag)
|
||||
}
|
||||
|
||||
func add(_ hashtag: Hashtag) {
|
||||
if isSaved(hashtag) {
|
||||
return
|
||||
}
|
||||
savedHashtags.append(hashtag)
|
||||
SavedHashtagsManager.save()
|
||||
NotificationCenter.default.post(name: .savedHashtagsChanged, object: nil)
|
||||
}
|
||||
|
||||
func remove(_ hashtag: Hashtag) {
|
||||
guard isSaved(hashtag) else { return }
|
||||
savedHashtags.removeAll(where: { $0.name == hashtag.name })
|
||||
SavedHashtagsManager.save()
|
||||
NotificationCenter.default.post(name: .savedHashtagsChanged, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension Foundation.Notification.Name {
|
||||
static let savedHashtagsChanged = Notification.Name("savedHashtagsChanged")
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// AddSavedHashtagViewController.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 12/19/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Pachyderm
|
||||
|
||||
class AddSavedHashtagViewController: SearchResultsViewController {
|
||||
|
||||
var searchController: UISearchController!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
delegate = self
|
||||
onlySections = [.hashtags]
|
||||
|
||||
searchController = UISearchController(searchResultsController: nil)
|
||||
searchController.obscuresBackgroundDuringPresentation = false
|
||||
searchController.hidesNavigationBarDuringPresentation = false
|
||||
searchController.searchBar.autocapitalizationType = .none
|
||||
searchController.searchBar.placeholder = NSLocalizedString("Search for hashtags to save", comment: "add saved hashtag search field placeholder")
|
||||
searchController.searchBar.delegate = self
|
||||
|
||||
definesPresentationContext = true
|
||||
|
||||
navigationItem.searchController = searchController
|
||||
navigationItem.hidesSearchBarWhenScrolling = false
|
||||
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonPressed))
|
||||
}
|
||||
|
||||
override func performSearch(query: String?) {
|
||||
if let query = query, !query.starts(with: "#") {
|
||||
super.performSearch(query: "#\(query)")
|
||||
} else {
|
||||
super.performSearch(query: query)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Interaction
|
||||
|
||||
@objc func cancelButtonPressed() {
|
||||
dismiss(animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension AddSavedHashtagViewController: SearchResultsViewControllerDelegate {
|
||||
func selectedSearchResult(hashtag: Hashtag) {
|
||||
SavedHashtagsManager.shared.add(hashtag)
|
||||
dismiss(animated: true)
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case let .list(list):
|
||||
cell.imageView!.image = nil
|
||||
cell.imageView!.image = UIImage(systemName: "list.bullet")
|
||||
cell.textLabel!.text = list.title
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
|
@ -51,6 +51,16 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
cell.imageView!.image = UIImage(systemName: "plus")
|
||||
cell.textLabel!.text = NSLocalizedString("New List...", comment: "new list nav item title")
|
||||
cell.accessoryType = .none
|
||||
|
||||
case let .savedHashtag(hashtag):
|
||||
cell.imageView!.image = UIImage(systemName: "number")
|
||||
cell.textLabel!.text = hashtag.name
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .addSavedHashtag:
|
||||
cell.imageView!.image = UIImage(systemName: "plus")
|
||||
cell.textLabel!.text = NSLocalizedString("Save Hashtag...", comment: "save hashtag nav item title")
|
||||
cell.accessoryType = .none
|
||||
}
|
||||
|
||||
return cell
|
||||
|
@ -58,9 +68,10 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
dataSource.exploreController = self
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||
snapshot.appendSections([.bookmarks, .lists])
|
||||
snapshot.appendSections([.bookmarks, .lists, .savedHashtags])
|
||||
snapshot.appendItems([.bookmarks], toSection: .bookmarks)
|
||||
snapshot.appendItems([.addList], toSection: .lists)
|
||||
snapshot.appendItems(SavedHashtagsManager.shared.sorted.map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||
// the initial, static items should not be displayed with an animation
|
||||
UIView.performWithoutAnimation {
|
||||
dataSource.apply(snapshot)
|
||||
|
@ -77,6 +88,8 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
navigationItem.searchController = searchController
|
||||
navigationItem.hidesSearchBarWhenScrolling = false
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(savedHashtagsChanged), name: .savedHashtagsChanged, object: nil)
|
||||
|
||||
reloadLists()
|
||||
}
|
||||
|
||||
|
@ -88,8 +101,7 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
}
|
||||
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
snapshot.deleteSections([.lists])
|
||||
snapshot.appendSections([.lists])
|
||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .lists))
|
||||
snapshot.appendItems(lists.map { .list($0) } + [.addList], toSection: .lists)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
@ -98,6 +110,39 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
@objc func savedHashtagsChanged() {
|
||||
var snapshot = dataSource.snapshot()
|
||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedHashtags))
|
||||
snapshot.appendItems(SavedHashtagsManager.shared.sorted.map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||
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)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "delete list alert cancel button"), style: .cancel, handler: nil))
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Delete List", comment: "delete list alert confirm button"), style: .destructive, handler: { (_) in
|
||||
|
||||
let request = List.delete(list)
|
||||
MastodonController.client.run(request) { (response) in
|
||||
guard case .success(_, _) = response else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
var snapshot = self.dataSource.snapshot()
|
||||
snapshot.deleteItems([.list(list)])
|
||||
DispatchQueue.main.async {
|
||||
self.dataSource.apply(snapshot)
|
||||
}
|
||||
}
|
||||
}))
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
func removeSavedHashtag(_ hashtag: Hashtag) {
|
||||
SavedHashtagsManager.shared.remove(hashtag)
|
||||
}
|
||||
|
||||
// MARK: - Table view delegate
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
@ -133,6 +178,14 @@ class ExploreViewController: EnhancedTableViewController {
|
|||
}
|
||||
}))
|
||||
present(alert, animated: true)
|
||||
|
||||
case let .savedHashtag(hashtag):
|
||||
show(HashtagTimelineViewController(for: hashtag), sender: nil)
|
||||
|
||||
case .addSavedHashtag:
|
||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
let navController = UINavigationController(rootViewController: AddSavedHashtagViewController())
|
||||
present(navController, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,11 +199,14 @@ extension ExploreViewController {
|
|||
enum Section: CaseIterable {
|
||||
case bookmarks
|
||||
case lists
|
||||
case savedHashtags
|
||||
}
|
||||
enum Item: Hashable {
|
||||
case bookmarks
|
||||
case list(List)
|
||||
case addList
|
||||
case savedHashtag(Hashtag)
|
||||
case addSavedHashtag
|
||||
|
||||
static func == (lhs: ExploreViewController.Item, rhs: ExploreViewController.Item) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
|
@ -160,6 +216,10 @@ extension ExploreViewController {
|
|||
return a.id == b.id
|
||||
case (.addList, .addList):
|
||||
return true
|
||||
case let (.savedHashtag(a), .savedHashtag(b)):
|
||||
return a == b
|
||||
case (.addSavedHashtag, .addSavedHashtag):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
@ -173,6 +233,11 @@ extension ExploreViewController {
|
|||
hasher.combine(list.id)
|
||||
case .addList:
|
||||
hasher.combine("addList")
|
||||
case let .savedHashtag(hashtag):
|
||||
hasher.combine("savedHashtag")
|
||||
hasher.combine(hashtag.name)
|
||||
case .addSavedHashtag:
|
||||
hasher.combine("addSavedHashtag")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,43 +250,39 @@ extension ExploreViewController {
|
|||
switch section {
|
||||
case 1:
|
||||
return NSLocalizedString("Lists", comment: "explore lists section title")
|
||||
case 2:
|
||||
return NSLocalizedString("Saved Hashtags", comment: "explore saved hashtags section title")
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||
if case .list(_) = itemIdentifier(for: indexPath) {
|
||||
switch itemIdentifier(for: indexPath) {
|
||||
case .list(_):
|
||||
return true
|
||||
}
|
||||
case .savedHashtag(_):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
guard editingStyle == .delete,
|
||||
case let .list(list) = itemIdentifier(for: indexPath) else {
|
||||
let exploreController = exploreController else {
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: "delete list alert cancel button"), style: .cancel, handler: nil))
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Delete List", comment: "delete list alert confirm button"), style: .destructive, handler: { (_) in
|
||||
|
||||
let request = List.delete(list)
|
||||
MastodonController.client.run(request) { (response) in
|
||||
guard case .success(_, _) = response else {
|
||||
fatalError()
|
||||
switch itemIdentifier(for: indexPath) {
|
||||
case let .list(list):
|
||||
exploreController.deleteList(list)
|
||||
case let .savedHashtag(hashtag):
|
||||
exploreController.removeSavedHashtag(hashtag)
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
var snapshot = self.snapshot()
|
||||
snapshot.deleteItems([.list(list)])
|
||||
DispatchQueue.main.async {
|
||||
self.apply(snapshot)
|
||||
}
|
||||
}
|
||||
}))
|
||||
self.exploreController?.present(alert, animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// HashtagTimelineViewController.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 12/19/19.
|
||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Pachyderm
|
||||
|
||||
class HashtagTimelineViewController: TimelineTableViewController {
|
||||
|
||||
let hashtag: Hashtag
|
||||
|
||||
var toggleSaveButton: UIBarButtonItem!
|
||||
var toggleSaveButtonTitle: String {
|
||||
if SavedHashtagsManager.shared.isSaved(hashtag) {
|
||||
return NSLocalizedString("Unsave", comment: "unsave hashtag button")
|
||||
} else {
|
||||
return NSLocalizedString("Save", comment: "save hashtag button")
|
||||
}
|
||||
}
|
||||
|
||||
init(for hashtag: Hashtag) {
|
||||
self.hashtag = hashtag
|
||||
|
||||
super.init(for: .tag(hashtag: hashtag.name))
|
||||
}
|
||||
|
||||
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(savedHashtagsChanged), name: .savedHashtagsChanged, object: nil)
|
||||
}
|
||||
|
||||
@objc func savedHashtagsChanged() {
|
||||
toggleSaveButton.title = toggleSaveButtonTitle
|
||||
}
|
||||
|
||||
// MARK: - Interaction
|
||||
|
||||
@objc func toggleSaveButtonPressed() {
|
||||
if SavedHashtagsManager.shared.isSaved(hashtag) {
|
||||
SavedHashtagsManager.shared.remove(hashtag)
|
||||
} else {
|
||||
SavedHashtagsManager.shared.add(hashtag)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -76,7 +76,7 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
|||
}
|
||||
|
||||
func selected(tag: Hashtag) {
|
||||
show(TimelineTableViewController(for: .tag(hashtag: tag.name)), sender: self)
|
||||
show(HashtagTimelineViewController(for: tag), sender: self)
|
||||
}
|
||||
|
||||
func selected(url: URL) {
|
||||
|
|
|
@ -181,7 +181,7 @@ class ContentLabel: LinkLabel {
|
|||
if let mention = getMention(for: url, text: text) {
|
||||
return ProfileTableViewController(accountID: mention.id)
|
||||
} else if let tag = getHashtag(for: url, text: text) {
|
||||
return TimelineTableViewController(for: .tag(hashtag: tag.name))
|
||||
return HashtagTimelineViewController(for: tag)
|
||||
} else {
|
||||
return SFSafariViewController(url: url)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue