forked from shadowfacts/Tusker
parent
26f1aafa15
commit
ff97b0f76d
|
@ -34,51 +34,76 @@ class SavedDataManager: Codable {
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
private var savedHashtags: [Hashtag] = [] {
|
private var savedHashtags: [String: [Hashtag]] = [:] {
|
||||||
didSet {
|
didSet {
|
||||||
SavedDataManager.save()
|
SavedDataManager.save()
|
||||||
NotificationCenter.default.post(name: .savedHashtagsChanged, object: nil)
|
NotificationCenter.default.post(name: .savedHashtagsChanged, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sortedHashtags: [Hashtag] {
|
|
||||||
return savedHashtags.sorted(by: { $0.name < $1.name })
|
private var savedInstances: [String: [URL]] = [:] {
|
||||||
}
|
|
||||||
|
|
||||||
private(set) var savedInstances: [URL] = [] {
|
|
||||||
didSet {
|
didSet {
|
||||||
SavedDataManager.save()
|
SavedDataManager.save()
|
||||||
NotificationCenter.default.post(name: .savedInstancesChanged, object: nil)
|
NotificationCenter.default.post(name: .savedInstancesChanged, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSaved(hashtag: Hashtag) -> Bool {
|
func sortedHashtags(for account: LocalData.UserAccountInfo) -> [Hashtag] {
|
||||||
return savedHashtags.contains(hashtag)
|
if let hashtags = savedHashtags[account.id] {
|
||||||
|
return hashtags.sorted(by: { $0.name < $1.name })
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(hashtag: Hashtag) {
|
func isSaved(hashtag: Hashtag, for account: LocalData.UserAccountInfo) -> Bool {
|
||||||
if isSaved(hashtag: hashtag) {
|
return savedHashtags[account.id]?.contains(hashtag) ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(hashtag: Hashtag, for account: LocalData.UserAccountInfo) {
|
||||||
|
if isSaved(hashtag: hashtag, for: account) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
savedHashtags.append(hashtag)
|
if var saved = savedHashtags[account.id] {
|
||||||
|
saved.append(hashtag)
|
||||||
|
savedHashtags[account.id] = saved
|
||||||
|
} else {
|
||||||
|
savedHashtags[account.id] = [hashtag]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func remove(hashtag: Hashtag) {
|
func remove(hashtag: Hashtag, for account: LocalData.UserAccountInfo) {
|
||||||
guard isSaved(hashtag: hashtag) else { return }
|
guard isSaved(hashtag: hashtag, for: account) else { return }
|
||||||
savedHashtags.removeAll(where: { $0.name == hashtag.name })
|
if var saved = savedHashtags[account.id] {
|
||||||
|
saved.removeAll(where: { $0.name == hashtag.name })
|
||||||
|
savedHashtags[account.id] = saved
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSaved(instance url: URL) -> Bool {
|
func savedInstances(for account: LocalData.UserAccountInfo) -> [URL] {
|
||||||
return savedInstances.contains(url)
|
return savedInstances[account.id] ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
func add(instance url: URL) {
|
func isSaved(instance url: URL, for account: LocalData.UserAccountInfo) -> Bool {
|
||||||
if isSaved(instance: url) { return }
|
return savedInstances[account.id]?.contains(url) ?? false
|
||||||
savedInstances.append(url)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func remove(instance url: URL) {
|
func add(instance url: URL, for account: LocalData.UserAccountInfo) {
|
||||||
guard isSaved(instance: url) else { return }
|
if isSaved(instance: url, for: account) { return }
|
||||||
savedInstances.removeAll(where: { $0 == url })
|
if var saved = savedInstances[account.id] {
|
||||||
|
saved.append(url)
|
||||||
|
savedInstances[account.id] = saved
|
||||||
|
} else {
|
||||||
|
savedInstances[account.id] = [url]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(instance url: URL, for account: LocalData.UserAccountInfo) {
|
||||||
|
guard isSaved(instance: url, for: account) else { return }
|
||||||
|
if var saved = savedInstances[account.id] {
|
||||||
|
saved.removeAll(where: { $0 == url })
|
||||||
|
savedInstances[account.id] = saved
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ class AddSavedHashtagViewController: SearchResultsViewController {
|
||||||
|
|
||||||
extension AddSavedHashtagViewController: SearchResultsViewControllerDelegate {
|
extension AddSavedHashtagViewController: SearchResultsViewControllerDelegate {
|
||||||
func selectedSearchResult(hashtag: Hashtag) {
|
func selectedSearchResult(hashtag: Hashtag) {
|
||||||
SavedDataManager.shared.add(hashtag: hashtag)
|
SavedDataManager.shared.add(hashtag: hashtag, for: mastodonController.accountInfo!)
|
||||||
dismiss(animated: true)
|
dismiss(animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,12 +81,14 @@ class ExploreViewController: EnhancedTableViewController {
|
||||||
})
|
})
|
||||||
dataSource.exploreController = self
|
dataSource.exploreController = self
|
||||||
|
|
||||||
|
let account = mastodonController.accountInfo!
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
snapshot.appendSections([.bookmarks, .lists, .savedHashtags, .savedInstances])
|
snapshot.appendSections([.bookmarks, .lists, .savedHashtags, .savedInstances])
|
||||||
snapshot.appendItems([.bookmarks], toSection: .bookmarks)
|
snapshot.appendItems([.bookmarks], toSection: .bookmarks)
|
||||||
snapshot.appendItems([.addList], toSection: .lists)
|
snapshot.appendItems([.addList], toSection: .lists)
|
||||||
snapshot.appendItems(SavedDataManager.shared.sortedHashtags.map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||||
snapshot.appendItems(SavedDataManager.shared.savedInstances.map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
||||||
// the initial, static items should not be displayed with an animation
|
// the initial, static items should not be displayed with an animation
|
||||||
UIView.performWithoutAnimation {
|
UIView.performWithoutAnimation {
|
||||||
dataSource.apply(snapshot)
|
dataSource.apply(snapshot)
|
||||||
|
@ -127,16 +129,18 @@ class ExploreViewController: EnhancedTableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func savedHashtagsChanged() {
|
@objc func savedHashtagsChanged() {
|
||||||
|
let account = mastodonController.accountInfo!
|
||||||
var snapshot = dataSource.snapshot()
|
var snapshot = dataSource.snapshot()
|
||||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedHashtags))
|
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedHashtags))
|
||||||
snapshot.appendItems(SavedDataManager.shared.sortedHashtags.map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
snapshot.appendItems(SavedDataManager.shared.sortedHashtags(for: account).map { .savedHashtag($0) } + [.addSavedHashtag], toSection: .savedHashtags)
|
||||||
dataSource.apply(snapshot)
|
dataSource.apply(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func savedInstancesChanged() {
|
@objc func savedInstancesChanged() {
|
||||||
|
let account = mastodonController.accountInfo!
|
||||||
var snapshot = dataSource.snapshot()
|
var snapshot = dataSource.snapshot()
|
||||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedInstances))
|
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .savedInstances))
|
||||||
snapshot.appendItems(SavedDataManager.shared.savedInstances.map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
snapshot.appendItems(SavedDataManager.shared.savedInstances(for: account).map { .savedInstance($0) } + [.findInstance], toSection: .savedInstances)
|
||||||
dataSource.apply(snapshot)
|
dataSource.apply(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,11 +167,13 @@ class ExploreViewController: EnhancedTableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeSavedHashtag(_ hashtag: Hashtag) {
|
func removeSavedHashtag(_ hashtag: Hashtag) {
|
||||||
SavedDataManager.shared.remove(hashtag: hashtag)
|
let account = mastodonController.accountInfo!
|
||||||
|
SavedDataManager.shared.remove(hashtag: hashtag, for: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeSavedInstance(_ instanceURL: URL) {
|
func removeSavedInstance(_ instanceURL: URL) {
|
||||||
SavedDataManager.shared.remove(instance: instanceURL)
|
let account = mastodonController.accountInfo!
|
||||||
|
SavedDataManager.shared.remove(instance: instanceURL, for: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Table view delegate
|
// MARK: - Table view delegate
|
||||||
|
@ -217,11 +223,11 @@ class ExploreViewController: EnhancedTableViewController {
|
||||||
present(navController, animated: true)
|
present(navController, animated: true)
|
||||||
|
|
||||||
case let .savedInstance(url):
|
case let .savedInstance(url):
|
||||||
show(InstanceTimelineViewController(for: url), sender: nil)
|
show(InstanceTimelineViewController(for: url, parentMastodonController: mastodonController), sender: nil)
|
||||||
|
|
||||||
case .findInstance:
|
case .findInstance:
|
||||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||||
let findController = FindInstanceViewController()
|
let findController = FindInstanceViewController(parentMastodonController: mastodonController)
|
||||||
findController.instanceTimelineDelegate = self
|
findController.instanceTimelineDelegate = self
|
||||||
let navController = UINavigationController(rootViewController: findController)
|
let navController = UINavigationController(rootViewController: findController)
|
||||||
present(navController, animated: true)
|
present(navController, animated: true)
|
||||||
|
@ -348,7 +354,7 @@ extension ExploreViewController {
|
||||||
extension ExploreViewController: InstanceTimelineViewControllerDelegate {
|
extension ExploreViewController: InstanceTimelineViewControllerDelegate {
|
||||||
func didSaveInstance(url: URL) {
|
func didSaveInstance(url: URL) {
|
||||||
dismiss(animated: true) {
|
dismiss(animated: true) {
|
||||||
self.show(InstanceTimelineViewController(for: url), sender: nil)
|
self.show(InstanceTimelineViewController(for: url, parentMastodonController: self.mastodonController), sender: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,20 @@ import UIKit
|
||||||
|
|
||||||
class FindInstanceViewController: InstanceSelectorTableViewController {
|
class FindInstanceViewController: InstanceSelectorTableViewController {
|
||||||
|
|
||||||
|
weak var parentMastodonController: MastodonController?
|
||||||
|
|
||||||
var instanceTimelineDelegate: InstanceTimelineViewControllerDelegate?
|
var instanceTimelineDelegate: InstanceTimelineViewControllerDelegate?
|
||||||
|
|
||||||
|
init(parentMastodonController: MastodonController) {
|
||||||
|
self.parentMastodonController = parentMastodonController
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
@ -32,7 +44,7 @@ class FindInstanceViewController: InstanceSelectorTableViewController {
|
||||||
|
|
||||||
extension FindInstanceViewController: InstanceSelectorTableViewControllerDelegate {
|
extension FindInstanceViewController: InstanceSelectorTableViewControllerDelegate {
|
||||||
func didSelectInstance(url: URL) {
|
func didSelectInstance(url: URL) {
|
||||||
let instanceTimelineController = InstanceTimelineViewController(for: url)
|
let instanceTimelineController = InstanceTimelineViewController(for: url, parentMastodonController: parentMastodonController!)
|
||||||
instanceTimelineController.delegate = instanceTimelineDelegate
|
instanceTimelineController.delegate = instanceTimelineDelegate
|
||||||
show(instanceTimelineController, sender: self)
|
show(instanceTimelineController, sender: self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class HashtagTimelineViewController: TimelineTableViewController {
|
||||||
|
|
||||||
var toggleSaveButton: UIBarButtonItem!
|
var toggleSaveButton: UIBarButtonItem!
|
||||||
var toggleSaveButtonTitle: String {
|
var toggleSaveButtonTitle: String {
|
||||||
if SavedDataManager.shared.isSaved(hashtag: hashtag) {
|
if SavedDataManager.shared.isSaved(hashtag: hashtag, for: mastodonController.accountInfo!) {
|
||||||
return NSLocalizedString("Unsave", comment: "unsave hashtag button")
|
return NSLocalizedString("Unsave", comment: "unsave hashtag button")
|
||||||
} else {
|
} else {
|
||||||
return NSLocalizedString("Save", comment: "save hashtag button")
|
return NSLocalizedString("Save", comment: "save hashtag button")
|
||||||
|
@ -48,10 +48,10 @@ class HashtagTimelineViewController: TimelineTableViewController {
|
||||||
// MARK: - Interaction
|
// MARK: - Interaction
|
||||||
|
|
||||||
@objc func toggleSaveButtonPressed() {
|
@objc func toggleSaveButtonPressed() {
|
||||||
if SavedDataManager.shared.isSaved(hashtag: hashtag) {
|
if SavedDataManager.shared.isSaved(hashtag: hashtag, for: mastodonController.accountInfo!) {
|
||||||
SavedDataManager.shared.remove(hashtag: hashtag)
|
SavedDataManager.shared.remove(hashtag: hashtag, for: mastodonController.accountInfo!)
|
||||||
} else {
|
} else {
|
||||||
SavedDataManager.shared.add(hashtag: hashtag)
|
SavedDataManager.shared.add(hashtag: hashtag, for: mastodonController.accountInfo!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,21 +17,25 @@ class InstanceTimelineViewController: TimelineTableViewController {
|
||||||
|
|
||||||
weak var delegate: InstanceTimelineViewControllerDelegate?
|
weak var delegate: InstanceTimelineViewControllerDelegate?
|
||||||
|
|
||||||
|
weak var parentMastodonController: MastodonController?
|
||||||
|
|
||||||
let instanceURL: URL
|
let instanceURL: URL
|
||||||
let instanceMastodonController: MastodonController
|
let instanceMastodonController: MastodonController
|
||||||
|
|
||||||
var toggleSaveButton: UIBarButtonItem!
|
var toggleSaveButton: UIBarButtonItem!
|
||||||
var toggleSaveButtonTitle: String {
|
var toggleSaveButtonTitle: String {
|
||||||
if SavedDataManager.shared.isSaved(instance: instanceURL) {
|
if SavedDataManager.shared.isSaved(instance: instanceURL, for: parentMastodonController!.accountInfo!) {
|
||||||
return NSLocalizedString("Unsave", comment: "unsave instance button")
|
return NSLocalizedString("Unsave", comment: "unsave instance button")
|
||||||
} else {
|
} else {
|
||||||
return NSLocalizedString("Save", comment: "save instance button")
|
return NSLocalizedString("Save", comment: "save instance button")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(for url: URL) {
|
init(for url: URL, parentMastodonController: MastodonController) {
|
||||||
self.instanceURL = url
|
self.parentMastodonController = parentMastodonController
|
||||||
|
|
||||||
|
self.instanceURL = url
|
||||||
|
|
||||||
// the timeline VC only stores a weak reference to it, so we need to store a strong reference to make sure it's not released immediately
|
// the timeline VC only stores a weak reference to it, so we need to store a strong reference to make sure it's not released immediately
|
||||||
instanceMastodonController = MastodonController(instanceURL: url)
|
instanceMastodonController = MastodonController(instanceURL: url)
|
||||||
|
|
||||||
|
@ -72,11 +76,11 @@ class InstanceTimelineViewController: TimelineTableViewController {
|
||||||
|
|
||||||
// MARK: - Interaction
|
// MARK: - Interaction
|
||||||
@objc func toggleSaveButtonPressed() {
|
@objc func toggleSaveButtonPressed() {
|
||||||
if SavedDataManager.shared.isSaved(instance: instanceURL) {
|
if SavedDataManager.shared.isSaved(instance: instanceURL, for: parentMastodonController!.accountInfo!) {
|
||||||
SavedDataManager.shared.remove(instance: instanceURL)
|
SavedDataManager.shared.remove(instance: instanceURL, for: parentMastodonController!.accountInfo!)
|
||||||
delegate?.didUnsaveInstance(url: instanceURL)
|
delegate?.didUnsaveInstance(url: instanceURL)
|
||||||
} else {
|
} else {
|
||||||
SavedDataManager.shared.add(instance: instanceURL)
|
SavedDataManager.shared.add(instance: instanceURL, for: parentMastodonController!.accountInfo!)
|
||||||
delegate?.didSaveInstance(url: instanceURL)
|
delegate?.didSaveInstance(url: instanceURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue