forked from shadowfacts/Tusker
Use context menu for filter/sort on profile directory
This commit is contained in:
parent
46fbbdc99a
commit
f5385b0a1d
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum DirectoryOrder: String {
|
public enum DirectoryOrder: String, CaseIterable {
|
||||||
case active
|
case active
|
||||||
case new
|
case new
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */; };
|
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */; };
|
||||||
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8D212CC7CC009840C4 /* ImageCache.swift */; };
|
04DACE8E212CC7CC009840C4 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8D212CC7CC009840C4 /* ImageCache.swift */; };
|
||||||
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED00B021481ED800567C53 /* SteppedProgressView.swift */; };
|
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED00B021481ED800567C53 /* SteppedProgressView.swift */; };
|
||||||
D600613E25D07E170067FAD6 /* ProfileDirectoryFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D600613D25D07E170067FAD6 /* ProfileDirectoryFilterView.swift */; };
|
|
||||||
D6093F9B25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6093F9A25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift */; };
|
D6093F9B25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6093F9A25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift */; };
|
||||||
D6093FB025BE0B01004811E6 /* TrendingHashtagTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6093FAE25BE0B01004811E6 /* TrendingHashtagTableViewCell.swift */; };
|
D6093FB025BE0B01004811E6 /* TrendingHashtagTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6093FAE25BE0B01004811E6 /* TrendingHashtagTableViewCell.swift */; };
|
||||||
D6093FB125BE0B01004811E6 /* TrendingHashtagTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6093FAF25BE0B01004811E6 /* TrendingHashtagTableViewCell.xib */; };
|
D6093FB125BE0B01004811E6 /* TrendingHashtagTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6093FAF25BE0B01004811E6 /* TrendingHashtagTableViewCell.xib */; };
|
||||||
|
@ -283,6 +282,7 @@
|
||||||
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
||||||
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */; };
|
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */; };
|
||||||
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; };
|
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; };
|
||||||
|
D6E1EEF4285443EF00D20549 /* UIAction+Subtitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E1EEF3285443EF00D20549 /* UIAction+Subtitle.swift */; };
|
||||||
D6E343AB265AAD6B00C4AA01 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D6E343AA265AAD6B00C4AA01 /* Media.xcassets */; };
|
D6E343AB265AAD6B00C4AA01 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D6E343AA265AAD6B00C4AA01 /* Media.xcassets */; };
|
||||||
D6E343AD265AAD6B00C4AA01 /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E343AC265AAD6B00C4AA01 /* ActionViewController.swift */; };
|
D6E343AD265AAD6B00C4AA01 /* ActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E343AC265AAD6B00C4AA01 /* ActionViewController.swift */; };
|
||||||
D6E343B0265AAD6B00C4AA01 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6E343AE265AAD6B00C4AA01 /* MainInterface.storyboard */; };
|
D6E343B0265AAD6B00C4AA01 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D6E343AE265AAD6B00C4AA01 /* MainInterface.storyboard */; };
|
||||||
|
@ -366,7 +366,6 @@
|
||||||
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = "<group>"; };
|
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = "<group>"; };
|
||||||
04DACE8D212CC7CC009840C4 /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
|
04DACE8D212CC7CC009840C4 /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
|
||||||
04ED00B021481ED800567C53 /* SteppedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SteppedProgressView.swift; sourceTree = "<group>"; };
|
04ED00B021481ED800567C53 /* SteppedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SteppedProgressView.swift; sourceTree = "<group>"; };
|
||||||
D600613D25D07E170067FAD6 /* ProfileDirectoryFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileDirectoryFilterView.swift; sourceTree = "<group>"; };
|
|
||||||
D6093F9A25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagSearchResultsViewController.swift; sourceTree = "<group>"; };
|
D6093F9A25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagSearchResultsViewController.swift; sourceTree = "<group>"; };
|
||||||
D6093FAE25BE0B01004811E6 /* TrendingHashtagTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingHashtagTableViewCell.swift; sourceTree = "<group>"; };
|
D6093FAE25BE0B01004811E6 /* TrendingHashtagTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingHashtagTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D6093FAF25BE0B01004811E6 /* TrendingHashtagTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TrendingHashtagTableViewCell.xib; sourceTree = "<group>"; };
|
D6093FAF25BE0B01004811E6 /* TrendingHashtagTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TrendingHashtagTableViewCell.xib; sourceTree = "<group>"; };
|
||||||
|
@ -635,6 +634,7 @@
|
||||||
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
||||||
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakArray.swift; sourceTree = "<group>"; };
|
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakArray.swift; sourceTree = "<group>"; };
|
||||||
D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = "<group>"; };
|
D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = "<group>"; };
|
||||||
|
D6E1EEF3285443EF00D20549 /* UIAction+Subtitle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAction+Subtitle.swift"; sourceTree = "<group>"; };
|
||||||
D6E343A8265AAD6B00C4AA01 /* OpenInTusker.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OpenInTusker.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
D6E343A8265AAD6B00C4AA01 /* OpenInTusker.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OpenInTusker.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D6E343AA265AAD6B00C4AA01 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
|
D6E343AA265AAD6B00C4AA01 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
|
||||||
D6E343AC265AAD6B00C4AA01 /* ActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionViewController.swift; sourceTree = "<group>"; };
|
D6E343AC265AAD6B00C4AA01 /* ActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -806,7 +806,6 @@
|
||||||
D693A72925CF8C1E003A14E2 /* ProfileDirectoryViewController.swift */,
|
D693A72925CF8C1E003A14E2 /* ProfileDirectoryViewController.swift */,
|
||||||
D693A72D25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift */,
|
D693A72D25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.swift */,
|
||||||
D693A72E25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib */,
|
D693A72E25CF91C6003A14E2 /* FeaturedProfileCollectionViewCell.xib */,
|
||||||
D600613D25D07E170067FAD6 /* ProfileDirectoryFilterView.swift */,
|
|
||||||
);
|
);
|
||||||
path = Explore;
|
path = Explore;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1124,6 +1123,7 @@
|
||||||
D6620ACD2511A0ED00312CA0 /* StatusStateResolver.swift */,
|
D6620ACD2511A0ED00312CA0 /* StatusStateResolver.swift */,
|
||||||
D69693F32585941A00F4E116 /* UIWindowSceneDelegate+Close.swift */,
|
D69693F32585941A00F4E116 /* UIWindowSceneDelegate+Close.swift */,
|
||||||
D62E9984279CA23900C26176 /* URLSession+Development.swift */,
|
D62E9984279CA23900C26176 /* URLSession+Development.swift */,
|
||||||
|
D6E1EEF3285443EF00D20549 /* UIAction+Subtitle.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1744,7 +1744,6 @@
|
||||||
D626493523BD94CE00612E6E /* CompositionAttachmentData.swift in Sources */,
|
D626493523BD94CE00612E6E /* CompositionAttachmentData.swift in Sources */,
|
||||||
D6531DF0246B867E000F9538 /* GifvAttachmentViewController.swift in Sources */,
|
D6531DF0246B867E000F9538 /* GifvAttachmentViewController.swift in Sources */,
|
||||||
D6285B5321EA708700FE4B39 /* StatusFormat.swift in Sources */,
|
D6285B5321EA708700FE4B39 /* StatusFormat.swift in Sources */,
|
||||||
D600613E25D07E170067FAD6 /* ProfileDirectoryFilterView.swift in Sources */,
|
|
||||||
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */,
|
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */,
|
||||||
0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */,
|
0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */,
|
||||||
D662AEEF263A3B880082A153 /* PollFinishedTableViewCell.swift in Sources */,
|
D662AEEF263A3B880082A153 /* PollFinishedTableViewCell.swift in Sources */,
|
||||||
|
@ -1765,6 +1764,7 @@
|
||||||
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */,
|
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */,
|
||||||
D62E9989279DB2D100C26176 /* InstanceFeatures.swift in Sources */,
|
D62E9989279DB2D100C26176 /* InstanceFeatures.swift in Sources */,
|
||||||
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */,
|
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */,
|
||||||
|
D6E1EEF4285443EF00D20549 /* UIAction+Subtitle.swift in Sources */,
|
||||||
D69693FA25859A8000F4E116 /* ComposeSceneDelegate.swift in Sources */,
|
D69693FA25859A8000F4E116 /* ComposeSceneDelegate.swift in Sources */,
|
||||||
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
|
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
|
||||||
D66A77BB233838DC0058F1EC /* UIFont+Traits.swift in Sources */,
|
D66A77BB233838DC0058F1EC /* UIFont+Traits.swift in Sources */,
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// UIAction+Subtitle.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 6/10/22.
|
||||||
|
// Copyright © 2022 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension UIAction {
|
||||||
|
convenience init(title: String, subtitle: String?, image: UIImage?, state: UIAction.State, handler: @escaping UIActionHandler) {
|
||||||
|
if #available(iOS 15.0, *) {
|
||||||
|
self.init(title: title, subtitle: subtitle, image: image, identifier: nil, discoverabilityTitle: nil, attributes: [], state: state, handler: handler)
|
||||||
|
} else {
|
||||||
|
self.init(title: title, image: image, identifier: nil, discoverabilityTitle: nil, attributes: [], state: state, handler: handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -471,13 +471,3 @@ extension ComposeHostingController: ComposeDrawingViewControllerDelegate {
|
||||||
dismiss(animated: true)
|
dismiss(animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate extension UIAction {
|
|
||||||
convenience init(title: String, subtitle: String?, image: UIImage?, state: UIAction.State, handler: @escaping UIActionHandler) {
|
|
||||||
if #available(iOS 15.0, *) {
|
|
||||||
self.init(title: title, subtitle: subtitle, image: image, identifier: nil, discoverabilityTitle: nil, attributes: [], state: state, handler: handler)
|
|
||||||
} else {
|
|
||||||
self.init(title: title, image: image, identifier: nil, discoverabilityTitle: nil, attributes: [], state: state, handler: handler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
//
|
|
||||||
// ProfileDirectoryFilterView.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 2/7/21.
|
|
||||||
// Copyright © 2021 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Pachyderm
|
|
||||||
|
|
||||||
class ProfileDirectoryFilterView: UICollectionReusableView {
|
|
||||||
|
|
||||||
var onFilterChanged: ((Scope, DirectoryOrder) -> Void)?
|
|
||||||
|
|
||||||
private var scope: UISegmentedControl!
|
|
||||||
private var sort: UISegmentedControl!
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
scope = UISegmentedControl(items: ["Instance", NSLocalizedString("Everywhere", comment: "everywhere profile directory scope")])
|
|
||||||
scope.selectedSegmentIndex = 0
|
|
||||||
scope.addTarget(self, action: #selector(filterChanged), for: .valueChanged)
|
|
||||||
|
|
||||||
sort = UISegmentedControl(items: [
|
|
||||||
NSLocalizedString("Active", comment: "active profile directory sort"),
|
|
||||||
NSLocalizedString("New", comment: "new profile directory sort"),
|
|
||||||
])
|
|
||||||
sort.selectedSegmentIndex = 0
|
|
||||||
sort.addTarget(self, action: #selector(filterChanged), for: .valueChanged)
|
|
||||||
|
|
||||||
let fromLabel = UILabel()
|
|
||||||
fromLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
fromLabel.text = NSLocalizedString("From", comment: "profile directory scope label")
|
|
||||||
fromLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
|
||||||
fromLabel.textAlignment = .right
|
|
||||||
|
|
||||||
let sortLabel = UILabel()
|
|
||||||
sortLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
sortLabel.text = NSLocalizedString("Sort By", comment: "profile directory sort label")
|
|
||||||
sortLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
|
||||||
sortLabel.textAlignment = .right
|
|
||||||
|
|
||||||
let labelContainer = UIView()
|
|
||||||
labelContainer.addSubview(sortLabel)
|
|
||||||
labelContainer.addSubview(fromLabel)
|
|
||||||
|
|
||||||
let controlStack = UIStackView(arrangedSubviews: [sort, scope])
|
|
||||||
controlStack.axis = .vertical
|
|
||||||
controlStack.spacing = 8
|
|
||||||
|
|
||||||
let blurEffect = UIBlurEffect(style: .systemChromeMaterial)
|
|
||||||
let blurView = UIVisualEffectView(effect: blurEffect)
|
|
||||||
blurView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
addSubview(blurView)
|
|
||||||
|
|
||||||
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect, style: .label)
|
|
||||||
let vibrancyView = UIVisualEffectView(effect: vibrancyEffect)
|
|
||||||
vibrancyView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
blurView.contentView.addSubview(vibrancyView)
|
|
||||||
|
|
||||||
let filterStack = UIStackView(arrangedSubviews: [
|
|
||||||
labelContainer,
|
|
||||||
controlStack,
|
|
||||||
])
|
|
||||||
filterStack.axis = .horizontal
|
|
||||||
filterStack.spacing = 8
|
|
||||||
filterStack.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
vibrancyView.contentView.addSubview(filterStack)
|
|
||||||
|
|
||||||
let separator = UIView()
|
|
||||||
separator.backgroundColor = .separator
|
|
||||||
separator.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
addSubview(separator)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
fromLabel.leadingAnchor.constraint(equalTo: labelContainer.leadingAnchor),
|
|
||||||
fromLabel.trailingAnchor.constraint(equalTo: labelContainer.trailingAnchor),
|
|
||||||
fromLabel.centerYAnchor.constraint(equalTo: scope.centerYAnchor),
|
|
||||||
|
|
||||||
sortLabel.leadingAnchor.constraint(equalTo: labelContainer.leadingAnchor),
|
|
||||||
sortLabel.trailingAnchor.constraint(equalTo: labelContainer.trailingAnchor),
|
|
||||||
sortLabel.centerYAnchor.constraint(equalTo: sort.centerYAnchor),
|
|
||||||
|
|
||||||
blurView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
||||||
blurView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
||||||
blurView.topAnchor.constraint(equalTo: topAnchor),
|
|
||||||
blurView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
||||||
|
|
||||||
vibrancyView.leadingAnchor.constraint(equalTo: blurView.contentView.leadingAnchor),
|
|
||||||
vibrancyView.trailingAnchor.constraint(equalTo: blurView.contentView.trailingAnchor),
|
|
||||||
vibrancyView.topAnchor.constraint(equalTo: blurView.contentView.topAnchor),
|
|
||||||
vibrancyView.bottomAnchor.constraint(equalTo: blurView.contentView.bottomAnchor),
|
|
||||||
|
|
||||||
filterStack.leadingAnchor.constraint(equalToSystemSpacingAfter: vibrancyView.contentView.leadingAnchor, multiplier: 1),
|
|
||||||
vibrancyView.contentView.trailingAnchor.constraint(equalToSystemSpacingAfter: filterStack.trailingAnchor, multiplier: 1),
|
|
||||||
filterStack.topAnchor.constraint(equalToSystemSpacingBelow: vibrancyView.contentView.topAnchor, multiplier: 1),
|
|
||||||
vibrancyView.contentView.bottomAnchor.constraint(equalToSystemSpacingBelow: filterStack.bottomAnchor, multiplier: 1),
|
|
||||||
|
|
||||||
separator.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
||||||
separator.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
||||||
separator.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
||||||
separator.heightAnchor.constraint(equalToConstant: 0.5),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUI(mastodonController: MastodonController) {
|
|
||||||
scope.setTitle(mastodonController.accountInfo!.instanceURL.host!, forSegmentAt: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func filterChanged() {
|
|
||||||
let scope = Scope(rawValue: self.scope.selectedSegmentIndex)!
|
|
||||||
let order = sort.selectedSegmentIndex == 0 ? DirectoryOrder.active : .new
|
|
||||||
onFilterChanged?(scope, order)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ProfileDirectoryFilterView {
|
|
||||||
enum Scope: Int, Equatable {
|
|
||||||
case instance, everywhere
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,6 +16,9 @@ class ProfileDirectoryViewController: UIViewController {
|
||||||
private var collectionView: UICollectionView!
|
private var collectionView: UICollectionView!
|
||||||
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
|
||||||
|
|
||||||
|
private var scope: Scope = .everywhere
|
||||||
|
private var order: DirectoryOrder = .active
|
||||||
|
|
||||||
init(mastodonController: MastodonController) {
|
init(mastodonController: MastodonController) {
|
||||||
self.mastodonController = mastodonController
|
self.mastodonController = mastodonController
|
||||||
|
|
||||||
|
@ -31,14 +34,10 @@ class ProfileDirectoryViewController: UIViewController {
|
||||||
|
|
||||||
title = NSLocalizedString("Profile Directory", comment: "profile directory title")
|
title = NSLocalizedString("Profile Directory", comment: "profile directory title")
|
||||||
|
|
||||||
let configuration = UICollectionViewCompositionalLayoutConfiguration()
|
// todo: it would be nice if there were a better "filter" icon
|
||||||
configuration.boundarySupplementaryItems = [
|
navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "scope"), menu: nil)
|
||||||
NSCollectionLayoutBoundarySupplementaryItem(
|
updateFilterMenu()
|
||||||
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(100)),
|
|
||||||
elementKind: "filter",
|
|
||||||
alignment: .top
|
|
||||||
)
|
|
||||||
]
|
|
||||||
let layout = UICollectionViewCompositionalLayout(sectionProvider: { (sectionIndex, layoutEnvironment) in
|
let layout = UICollectionViewCompositionalLayout(sectionProvider: { (sectionIndex, layoutEnvironment) in
|
||||||
let itemHeight = NSCollectionLayoutDimension.absolute(200)
|
let itemHeight = NSCollectionLayoutDimension.absolute(200)
|
||||||
let itemWidth: NSCollectionLayoutDimension
|
let itemWidth: NSCollectionLayoutDimension
|
||||||
|
@ -60,19 +59,18 @@ class ProfileDirectoryViewController: UIViewController {
|
||||||
section.interGroupSpacing = 16
|
section.interGroupSpacing = 16
|
||||||
section.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)
|
section.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)
|
||||||
return section
|
return section
|
||||||
}, configuration: configuration)
|
})
|
||||||
|
|
||||||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
collectionView.backgroundColor = .secondarySystemBackground
|
collectionView.backgroundColor = .secondarySystemBackground
|
||||||
collectionView.register(UINib(nibName: "FeaturedProfileCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "featuredProfileCell")
|
collectionView.register(UINib(nibName: "FeaturedProfileCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "featuredProfileCell")
|
||||||
collectionView.register(ProfileDirectoryFilterView.self, forSupplementaryViewOfKind: "filter", withReuseIdentifier: "filter")
|
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
updateProfiles(local: true, order: .active)
|
updateProfiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
|
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
|
||||||
|
@ -82,26 +80,44 @@ class ProfileDirectoryViewController: UIViewController {
|
||||||
cell.updateUI(account: account)
|
cell.updateUI(account: account)
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
dataSource.supplementaryViewProvider = { (collectionView, elementKind, indexPath) in
|
|
||||||
guard elementKind == "filter" else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let filterView = collectionView.dequeueReusableSupplementaryView(ofKind: "filter", withReuseIdentifier: "filter", for: indexPath) as! ProfileDirectoryFilterView
|
|
||||||
filterView.updateUI(mastodonController: self.mastodonController)
|
|
||||||
filterView.onFilterChanged = { [weak self] (scope, order) in
|
|
||||||
guard let self = self else { return }
|
|
||||||
self.dataSource.apply(.init())
|
|
||||||
self.updateProfiles(local: scope == .instance, order: order)
|
|
||||||
}
|
|
||||||
return filterView
|
|
||||||
}
|
|
||||||
return dataSource
|
return dataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateProfiles(local: Bool, order: DirectoryOrder) {
|
private func updateFilterMenu() {
|
||||||
|
let scopeMenu = UIMenu(options: .displayInline, children: [
|
||||||
|
UIAction(title: "Everywhere", subtitle: "Users from the whole network", image: UIImage(systemName: "globe"), state: scope == .everywhere ? .on : .off, handler: { [unowned self] _ in
|
||||||
|
self.scope = .everywhere
|
||||||
|
self.updateFilterMenu()
|
||||||
|
self.updateProfiles()
|
||||||
|
}),
|
||||||
|
UIAction(title: mastodonController.accountInfo!.instanceURL.host!, subtitle: "Only users from your instance", image: UIImage(systemName: "house"), state: scope == .instance ? .on : .off, handler: { [unowned self] _ in
|
||||||
|
self.scope = .instance
|
||||||
|
self.updateFilterMenu()
|
||||||
|
self.updateProfiles()
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
let orderMenu = UIMenu(options: .displayInline, children: DirectoryOrder.allCases.map { order in
|
||||||
|
UIAction(title: order.title, subtitle: order.subtitle, image: nil, state: self.order == order ? .on : .off) { [unowned self] _ in
|
||||||
|
self.order = order
|
||||||
|
self.updateFilterMenu()
|
||||||
|
self.updateProfiles()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
navigationItem.rightBarButtonItem!.menu = UIMenu(children: [
|
||||||
|
scopeMenu,
|
||||||
|
orderMenu,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateProfiles() {
|
||||||
|
let scope = self.scope
|
||||||
|
let order = self.order
|
||||||
|
let local = scope == .everywhere
|
||||||
let request = Client.getFeaturedProfiles(local: local, order: order)
|
let request = Client.getFeaturedProfiles(local: local, order: order)
|
||||||
mastodonController.run(request) { (response) in
|
mastodonController.run(request) { (response) in
|
||||||
guard case let .success(accounts, _) = response else {
|
guard case let .success(accounts, _) = response,
|
||||||
|
self.scope == scope,
|
||||||
|
self.order == order else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,3 +204,28 @@ extension ProfileDirectoryViewController: UICollectionViewDragDelegate {
|
||||||
return [UIDragItem(itemProvider: provider)]
|
return [UIDragItem(itemProvider: provider)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ProfileDirectoryViewController {
|
||||||
|
enum Scope: CaseIterable {
|
||||||
|
case instance, everywhere
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension DirectoryOrder {
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case .active:
|
||||||
|
return "Active"
|
||||||
|
case .new:
|
||||||
|
return "New"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var subtitle: String {
|
||||||
|
switch self {
|
||||||
|
case .active:
|
||||||
|
return "Users who have posted lately"
|
||||||
|
case .new:
|
||||||
|
return "Recently joined users"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue