diff --git a/Pachyderm/Model/Hashtag.swift b/Pachyderm/Model/Hashtag.swift index 315f28d7..e77d5989 100644 --- a/Pachyderm/Model/Hashtag.swift +++ b/Pachyderm/Model/Hashtag.swift @@ -39,3 +39,13 @@ extension Hashtag { } } } + +extension Hashtag: Equatable, Hashable { + public static func ==(lhs: Hashtag, rhs: Hashtag) -> Bool { + return lhs.url == rhs.url + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(url) + } +} diff --git a/Pachyderm/Model/SearchResults.swift b/Pachyderm/Model/SearchResults.swift index 07806b82..3ee90764 100644 --- a/Pachyderm/Model/SearchResults.swift +++ b/Pachyderm/Model/SearchResults.swift @@ -11,7 +11,7 @@ import Foundation public class SearchResults: Decodable { public let accounts: [Account] public let statuses: [Status] - public let hashtags: [String] + public let hashtags: [Hashtag] private enum CodingKeys: String, CodingKey { case accounts diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 65890428..d5547754 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -69,6 +69,8 @@ D6109A0D214599E100432DC2 /* RequestRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6109A0C214599E100432DC2 /* RequestRange.swift */; }; D6109A0F21459B6900432DC2 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6109A0E21459B6900432DC2 /* Pagination.swift */; }; D6109A11214607D500432DC2 /* Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6109A10214607D500432DC2 /* Timeline.swift */; }; + D611C2CF232DC61100C86A49 /* HashtagTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D611C2CD232DC61100C86A49 /* HashtagTableViewCell.swift */; }; + D611C2D0232DC61100C86A49 /* HashtagTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D611C2CE232DC61100C86A49 /* HashtagTableViewCell.xib */; }; D6163F2C21AA0AF1008DAC41 /* MyProfileTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6163F2B21AA0AF1008DAC41 /* MyProfileTableViewController.swift */; }; D627FF76217E923E00CC0648 /* DraftsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627FF75217E923E00CC0648 /* DraftsManager.swift */; }; D627FF79217E950100CC0648 /* DraftsTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627FF78217E950100CC0648 /* DraftsTableViewController.xib */; }; @@ -322,6 +324,8 @@ D6109A0C214599E100432DC2 /* RequestRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestRange.swift; sourceTree = ""; }; D6109A0E21459B6900432DC2 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; D6109A10214607D500432DC2 /* Timeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Timeline.swift; sourceTree = ""; }; + D611C2CD232DC61100C86A49 /* HashtagTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTableViewCell.swift; sourceTree = ""; }; + D611C2CE232DC61100C86A49 /* HashtagTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HashtagTableViewCell.xib; sourceTree = ""; }; D6163F2B21AA0AF1008DAC41 /* MyProfileTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyProfileTableViewController.swift; sourceTree = ""; }; D627FF75217E923E00CC0648 /* DraftsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsManager.swift; sourceTree = ""; }; D627FF78217E950100CC0648 /* DraftsTableViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraftsTableViewController.xib; sourceTree = ""; }; @@ -661,6 +665,15 @@ path = Model; sourceTree = ""; }; + D611C2CC232DC5FC00C86A49 /* Hashtag Cell */ = { + isa = PBXGroup; + children = ( + D611C2CD232DC61100C86A49 /* HashtagTableViewCell.swift */, + D611C2CE232DC61100C86A49 /* HashtagTableViewCell.xib */, + ); + path = "Hashtag Cell"; + sourceTree = ""; + }; D627FF77217E94F200CC0648 /* Drafts */ = { isa = PBXGroup; children = ( @@ -1041,6 +1054,7 @@ D641C78B213DD92F004B4513 /* Profile Header */, D641C78C213DD937004B4513 /* Notifications */, D6A3BC872321F78000FD64D5 /* Account Cell */, + D611C2CC232DC5FC00C86A49 /* Hashtag Cell */, ); path = Views; sourceTree = ""; @@ -1403,6 +1417,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + D611C2D0232DC61100C86A49 /* HashtagTableViewCell.xib in Resources */, D6A3BC8B2321F79B00FD64D5 /* AccountTableViewCell.xib in Resources */, D627FF7D217E958900CC0648 /* DraftTableViewCell.xib in Resources */, D6A3BC7D232195C600FD64D5 /* ActionNotificationGroupTableViewCell.xib in Resources */, @@ -1529,6 +1544,7 @@ D6C7D27D22B6EBF800071952 /* AttachmentsContainerView.swift in Sources */, D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */, 0411610022B442870030A9B7 /* AttachmentViewController.swift in Sources */, + D611C2CF232DC61100C86A49 /* HashtagTableViewCell.swift in Sources */, D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */, D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */, D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */, diff --git a/Tusker/Screens/Search/SearchTableViewController.swift b/Tusker/Screens/Search/SearchTableViewController.swift index 3d2ea3ac..5f51d292 100644 --- a/Tusker/Screens/Search/SearchTableViewController.swift +++ b/Tusker/Screens/Search/SearchTableViewController.swift @@ -12,6 +12,7 @@ import Pachyderm fileprivate let accountCell = "accountCell" fileprivate let statusCell = "statusCell" +fileprivate let hashtagCell = "hashtagCell" class SearchTableViewController: EnhancedTableViewController { @@ -39,6 +40,7 @@ class SearchTableViewController: EnhancedTableViewController { tableView.register(UINib(nibName: "AccountTableViewCell", bundle: .main), forCellReuseIdentifier: accountCell) tableView.register(UINib(nibName: "StatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell) + tableView.register(UINib(nibName: "HashtagTableViewCell", bundle: .main), forCellReuseIdentifier: hashtagCell) dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in switch item { @@ -47,6 +49,11 @@ class SearchTableViewController: EnhancedTableViewController { cell.updateUI(accountID: id) cell.delegate = self return cell + case let .hashtag(tag): + let cell = tableView.dequeueReusableCell(withIdentifier: hashtagCell, for: indexPath) as! HashtagTableViewCell + cell.updateUI(hashtag: tag) + cell.delegate = self + return cell case let .status(id): let cell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as! StatusTableViewCell cell.updateUI(statusID: id) @@ -107,6 +114,10 @@ class SearchTableViewController: EnhancedTableViewController { snapshot.appendItems(results.accounts.map { Item.account($0.id) }, toSection: .accounts) MastodonCache.addAll(accounts: results.accounts) } + if !results.hashtags.isEmpty { + snapshot.appendSections([.hashtags]) + snapshot.appendItems(results.hashtags.map { Item.hashtag($0) }, toSection: .hashtags) + } if !results.statuses.isEmpty { snapshot.appendSections([.statuses]) snapshot.appendItems(results.statuses.map { Item.status($0.id) }, toSection: .statuses) @@ -122,12 +133,15 @@ class SearchTableViewController: EnhancedTableViewController { extension SearchTableViewController { enum Section: CaseIterable { case accounts + case hashtags case statuses - + var displayName: String { switch self { case .accounts: return NSLocalizedString("People", comment: "accounts search results section") + case .hashtags: + return NSLocalizedString("Hashtags", comment: "hashtag search results section") case .statuses: return NSLocalizedString("Posts", comment: "statuses search results section") } @@ -135,6 +149,7 @@ extension SearchTableViewController { } enum Item: Hashable { case account(String) + case hashtag(Hashtag) case status(String) } diff --git a/Tusker/Views/Hashtag Cell/HashtagTableViewCell.swift b/Tusker/Views/Hashtag Cell/HashtagTableViewCell.swift new file mode 100644 index 00000000..7f434f03 --- /dev/null +++ b/Tusker/Views/Hashtag Cell/HashtagTableViewCell.swift @@ -0,0 +1,34 @@ +// +// HashtagTableViewCell.swift +// Tusker +// +// Created by Shadowfacts on 9/14/19. +// Copyright © 2019 Shadowfacts. All rights reserved. +// + +import UIKit +import Pachyderm + +class HashtagTableViewCell: UITableViewCell { + + var delegate: TuskerNavigationDelegate? + + @IBOutlet weak var hashtagLabel: UILabel! + + var hashtag: Hashtag! + + func updateUI(hashtag: Hashtag) { + self.hashtag = hashtag + + hashtagLabel.text = "#\(hashtag.name)" + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + if selected { + delegate?.selected(tag: hashtag) + } + } + +} diff --git a/Tusker/Views/Hashtag Cell/HashtagTableViewCell.xib b/Tusker/Views/Hashtag Cell/HashtagTableViewCell.xib new file mode 100644 index 00000000..a38016d4 --- /dev/null +++ b/Tusker/Views/Hashtag Cell/HashtagTableViewCell.xib @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +