Compare commits
6 Commits
4b2776ee81
...
907cf08400
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 907cf08400 | |
Shadowfacts | e85d194e5f | |
Shadowfacts | cfeb87d2ba | |
Shadowfacts | e4f3735c9f | |
Shadowfacts | baa9dfe0f1 | |
Shadowfacts | 5e73439e7b |
|
@ -88,6 +88,10 @@
|
||||||
argument = "-com.apple.CoreData.ConcurrencyDebug 1"
|
argument = "-com.apple.CoreData.ConcurrencyDebug 1"
|
||||||
isEnabled = "YES">
|
isEnabled = "YES">
|
||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
|
<CommandLineArgument
|
||||||
|
argument = "-UIFocusLoggingEnabled YES"
|
||||||
|
isEnabled = "NO">
|
||||||
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = "-UIFocusLoopDebuggerEnabled YES"
|
argument = "-UIFocusLoopDebuggerEnabled YES"
|
||||||
isEnabled = "YES">
|
isEnabled = "YES">
|
||||||
|
|
|
@ -36,6 +36,7 @@ class AccountListViewController: UIViewController, CollectionViewController {
|
||||||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ class AssetCollectionViewController: UIViewController, UICollectionViewDelegate
|
||||||
collectionView.alwaysBounceVertical = true
|
collectionView.alwaysBounceVertical = true
|
||||||
collectionView.allowsMultipleSelection = true
|
collectionView.allowsMultipleSelection = true
|
||||||
collectionView.allowsSelection = true
|
collectionView.allowsSelection = true
|
||||||
|
collectionView.allowsFocus = true
|
||||||
|
|
||||||
collectionView.register(UINib(nibName: "AssetCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: reuseIdentifier)
|
collectionView.register(UINib(nibName: "AssetCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: reuseIdentifier)
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ class AssetCollectionsListViewController: UITableViewController {
|
||||||
tableView.register(UINib(nibName: "AllPhotosTableViewCell", bundle: .main), forCellReuseIdentifier: "allPhotosCell")
|
tableView.register(UINib(nibName: "AllPhotosTableViewCell", bundle: .main), forCellReuseIdentifier: "allPhotosCell")
|
||||||
tableView.register(UINib(nibName: "AlbumTableViewCell", bundle: .main), forCellReuseIdentifier: "albumCell")
|
tableView.register(UINib(nibName: "AlbumTableViewCell", bundle: .main), forCellReuseIdentifier: "albumCell")
|
||||||
|
|
||||||
|
tableView.allowsFocus = true
|
||||||
|
|
||||||
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
||||||
switch item {
|
switch item {
|
||||||
case .cameraRoll:
|
case .cameraRoll:
|
||||||
|
|
|
@ -41,6 +41,7 @@ class BookmarksTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
tableView.rowHeight = UITableView.automaticDimension
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
tableView.estimatedRowHeight = 140
|
tableView.estimatedRowHeight = 140
|
||||||
|
tableView.allowsFocus = true
|
||||||
|
|
||||||
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell)
|
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell)
|
||||||
|
|
||||||
|
|
|
@ -61,13 +61,13 @@ class ConversationTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
tableView.delegate = self
|
tableView.delegate = self
|
||||||
tableView.dataSource = self
|
tableView.dataSource = self
|
||||||
|
tableView.prefetchDataSource = self
|
||||||
|
|
||||||
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "statusCell")
|
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "statusCell")
|
||||||
tableView.register(UINib(nibName: "ConversationMainStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "mainStatusCell")
|
tableView.register(UINib(nibName: "ConversationMainStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "mainStatusCell")
|
||||||
tableView.register(UINib(nibName: "ExpandThreadTableViewCell", bundle: .main), forCellReuseIdentifier: "expandThreadCell")
|
tableView.register(UINib(nibName: "ExpandThreadTableViewCell", bundle: .main), forCellReuseIdentifier: "expandThreadCell")
|
||||||
|
|
||||||
tableView.prefetchDataSource = self
|
tableView.allowsFocus = true
|
||||||
|
|
||||||
tableView.backgroundColor = .secondarySystemBackground
|
tableView.backgroundColor = .secondarySystemBackground
|
||||||
// separators are disabled on the table view so we can re-add them ourselves
|
// separators are disabled on the table view so we can re-add them ourselves
|
||||||
// so they're not inserted in between statuses in the ame sub-thread
|
// so they're not inserted in between statuses in the ame sub-thread
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ExpandThreadTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
threadLinkView = UIView()
|
threadLinkView = UIView()
|
||||||
threadLinkView.translatesAutoresizingMaskIntoConstraints = false
|
threadLinkView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
threadLinkView.backgroundColor = tintColor.withAlphaComponent(0.5)
|
threadLinkView.backgroundColor = .tintColor.withAlphaComponent(0.5)
|
||||||
threadLinkView.layer.cornerRadius = 2.5
|
threadLinkView.layer.cornerRadius = 2.5
|
||||||
contentView.addSubview(threadLinkView)
|
contentView.addSubview(threadLinkView)
|
||||||
threadLinkViewFullHeightConstraint = threadLinkView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
|
threadLinkViewFullHeightConstraint = threadLinkView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 replies" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dcm-ll-GeE">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 replies" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dcm-ll-GeE">
|
||||||
<rect key="frame" x="108" y="12" width="65" height="20.5"/>
|
<rect key="frame" x="108" y="12" width="65" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" systemColor="systemBlueColor"/>
|
<color key="textColor" systemColor="tintColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
<systemColor name="separatorColor">
|
<systemColor name="separatorColor">
|
||||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</systemColor>
|
</systemColor>
|
||||||
<systemColor name="systemBlueColor">
|
<systemColor name="tintColor">
|
||||||
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</systemColor>
|
</systemColor>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -42,6 +42,7 @@ class AddSavedHashtagViewController: UIViewController {
|
||||||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
let sectionHeaderCell = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { (headerView, collectionView, indexPath) in
|
let sectionHeaderCell = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { (headerView, collectionView, indexPath) in
|
||||||
|
|
|
@ -50,6 +50,7 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate, Collect
|
||||||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
|
|
|
@ -68,6 +68,7 @@ class ProfileDirectoryViewController: UIViewController {
|
||||||
collectionView.register(UINib(nibName: "FeaturedProfileCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "featuredProfileCell")
|
collectionView.register(UINib(nibName: "FeaturedProfileCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "featuredProfileCell")
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
|
|
|
@ -40,6 +40,7 @@ class TrendingHashtagsViewController: UIViewController {
|
||||||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
let registration = UICollectionView.CellRegistration<TrendingHashtagCollectionViewCell, Hashtag> { cell, indexPath, hashtag in
|
let registration = UICollectionView.CellRegistration<TrendingHashtagCollectionViewCell, Hashtag> { cell, indexPath, hashtag in
|
||||||
|
|
|
@ -36,6 +36,7 @@ class TrendingLinksViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
tableView.register(TrendingLinkTableViewCell.self, forCellReuseIdentifier: "trendingLinkCell")
|
tableView.register(TrendingLinkTableViewCell.self, forCellReuseIdentifier: "trendingLinkCell")
|
||||||
tableView.estimatedRowHeight = 100
|
tableView.estimatedRowHeight = 100
|
||||||
|
tableView.allowsFocus = true
|
||||||
|
|
||||||
dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { tableView, indexPath, item in
|
dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { tableView, indexPath, item in
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "trendingLinkCell", for: indexPath) as! TrendingLinkTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "trendingLinkCell", for: indexPath) as! TrendingLinkTableViewCell
|
||||||
|
|
|
@ -62,12 +62,15 @@ class TrendingStatusesViewController: UIViewController {
|
||||||
}
|
}
|
||||||
let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
|
let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
|
||||||
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||||
section.contentInsetsReference = .readableContent
|
section.contentInsetsReference = .readableContent
|
||||||
|
}
|
||||||
return section
|
return section
|
||||||
}
|
}
|
||||||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
|
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ class EditListAccountsViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
tableView.rowHeight = UITableView.automaticDimension
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
tableView.estimatedRowHeight = 66
|
tableView.estimatedRowHeight = 66
|
||||||
|
tableView.allowsSelection = false
|
||||||
|
|
||||||
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
||||||
guard case let .account(id) = item else { fatalError() }
|
guard case let .account(id) = item else { fatalError() }
|
||||||
|
|
|
@ -55,7 +55,9 @@ class NotificationsTableViewController: DiffableTimelineLikeTableViewController<
|
||||||
tableView.register(UINib(nibName: "PollFinishedTableViewCell", bundle: .main), forCellReuseIdentifier: pollCell)
|
tableView.register(UINib(nibName: "PollFinishedTableViewCell", bundle: .main), forCellReuseIdentifier: pollCell)
|
||||||
tableView.register(UINib(nibName: "StatusUpdatedNotificationTableViewCell", bundle: .main), forCellReuseIdentifier: updatedCell)
|
tableView.register(UINib(nibName: "StatusUpdatedNotificationTableViewCell", bundle: .main), forCellReuseIdentifier: updatedCell)
|
||||||
tableView.register(UINib(nibName: "BasicTableViewCell", bundle: .main), forCellReuseIdentifier: unknownCell)
|
tableView.register(UINib(nibName: "BasicTableViewCell", bundle: .main), forCellReuseIdentifier: unknownCell)
|
||||||
|
|
||||||
tableView.cellLayoutMarginsFollowReadableWidth = true
|
tableView.cellLayoutMarginsFollowReadableWidth = true
|
||||||
|
tableView.allowsFocus = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private func request(range: RequestRange) -> Request<[Pachyderm.Notification]> {
|
private func request(range: RequestRange) -> Request<[Pachyderm.Notification]> {
|
||||||
|
|
|
@ -85,13 +85,16 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
||||||
return .list(using: .init(appearance: .plain), layoutEnvironment: environment)
|
return .list(using: .init(appearance: .plain), layoutEnvironment: environment)
|
||||||
} else {
|
} else {
|
||||||
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||||
section.contentInsetsReference = .readableContent
|
section.contentInsetsReference = .readableContent
|
||||||
|
}
|
||||||
return section
|
return section
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
|
|
||||||
registerTimelineLikeCells()
|
registerTimelineLikeCells()
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
|
@ -553,6 +556,15 @@ extension ProfileStatusesViewController: UICollectionViewDelegate {
|
||||||
func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
|
func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
|
||||||
MenuPreviewHelper.willPerformPreviewAction(animator: animator, presenter: self)
|
MenuPreviewHelper.willPerformPreviewAction(animator: animator, presenter: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, canFocusItemAt indexPath: IndexPath) -> Bool {
|
||||||
|
switch dataSource.itemIdentifier(for: indexPath) {
|
||||||
|
case .header(_), .loadingIndicator:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ProfileStatusesViewController: UICollectionViewDragDelegate {
|
extension ProfileStatusesViewController: UICollectionViewDragDelegate {
|
||||||
|
|
|
@ -83,6 +83,8 @@ class SearchResultsViewController: EnhancedTableViewController {
|
||||||
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell)
|
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell)
|
||||||
tableView.register(UINib(nibName: "HashtagTableViewCell", bundle: .main), forCellReuseIdentifier: hashtagCell)
|
tableView.register(UINib(nibName: "HashtagTableViewCell", bundle: .main), forCellReuseIdentifier: hashtagCell)
|
||||||
|
|
||||||
|
tableView.allowsFocus = true
|
||||||
|
|
||||||
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
||||||
switch item {
|
switch item {
|
||||||
case let .account(id):
|
case let .account(id):
|
||||||
|
|
|
@ -70,6 +70,7 @@ class SearchViewController: UIViewController {
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
collectionView.backgroundColor = .secondarySystemBackground
|
collectionView.backgroundColor = .secondarySystemBackground
|
||||||
|
collectionView.allowsFocus = true
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
|
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
|
|
|
@ -74,6 +74,7 @@ class StatusActionAccountListViewController: UIViewController, CollectionViewCon
|
||||||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
dataSource = createDataSource()
|
dataSource = createDataSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,12 +90,15 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
// just setting layout.configuration.contentInsetsReference doesn't work with UICollectionViewCompositionalLayout.list
|
// just setting layout.configuration.contentInsetsReference doesn't work with UICollectionViewCompositionalLayout.list
|
||||||
let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
|
let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
|
||||||
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
||||||
|
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||||
section.contentInsetsReference = .readableContent
|
section.contentInsetsReference = .readableContent
|
||||||
|
}
|
||||||
return section
|
return section
|
||||||
}
|
}
|
||||||
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dragDelegate = self
|
collectionView.dragDelegate = self
|
||||||
|
collectionView.allowsFocus = true
|
||||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
|
@ -353,10 +356,26 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private func loadStatusesToRestore(position: TimelinePosition) async -> Bool {
|
private func loadStatusesToRestore(position: TimelinePosition) async -> Bool {
|
||||||
|
{
|
||||||
|
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
|
crumb.message = "Original statusIDs before filtering"
|
||||||
|
crumb.data = [
|
||||||
|
"statusIDs": position.statusIDs,
|
||||||
|
]
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
|
}()
|
||||||
let unloaded = position.statusIDs.filter({ mastodonController.persistentContainer.status(for: $0) == nil })
|
let unloaded = position.statusIDs.filter({ mastodonController.persistentContainer.status(for: $0) == nil })
|
||||||
guard !unloaded.isEmpty else {
|
guard !unloaded.isEmpty else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
|
crumb.message = "Unloaded ids"
|
||||||
|
crumb.data = [
|
||||||
|
"unloaded": unloaded
|
||||||
|
]
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
|
}()
|
||||||
let results = await withTaskGroup(of: (String, Result<Status, Swift.Error>).self) { group -> [(String, Result<Status, Swift.Error>)] in
|
let results = await withTaskGroup(of: (String, Result<Status, Swift.Error>).self) { group -> [(String, Result<Status, Swift.Error>)] in
|
||||||
for id in unloaded {
|
for id in unloaded {
|
||||||
group.addTask {
|
group.addTask {
|
||||||
|
@ -377,6 +396,9 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let status):
|
case .success(let status):
|
||||||
statuses.append(status)
|
statuses.append(status)
|
||||||
|
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
|
crumb.message = "Loaded status \(id)"
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
let crumb = Breadcrumb(level: .error, category: "TimelineViewController")
|
let crumb = Breadcrumb(level: .error, category: "TimelineViewController")
|
||||||
crumb.message = "Error loading status"
|
crumb.message = "Error loading status"
|
||||||
|
@ -389,12 +411,14 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
}
|
}
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses, in: mastodonController.persistentContainer.viewContext)
|
await mastodonController.persistentContainer.addAll(statuses: statuses, in: mastodonController.persistentContainer.viewContext)
|
||||||
|
|
||||||
|
_ = {
|
||||||
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
crumb.message = "Original position statusIDs"
|
crumb.message = "Position statusIDs before filtering"
|
||||||
crumb.data = [
|
crumb.data = [
|
||||||
"statusIDs": position.statusIDs,
|
"statusIDs": position.statusIDs,
|
||||||
]
|
]
|
||||||
SentrySDK.addBreadcrumb(crumb: crumb)
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
|
}()
|
||||||
|
|
||||||
// update the timeline position in case some statuses couldn't be loaded
|
// update the timeline position in case some statuses couldn't be loaded
|
||||||
if let center = position.centerStatusID {
|
if let center = position.centerStatusID {
|
||||||
|
@ -408,12 +432,14 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
!unloaded.contains(id) || statuses.contains(where: { $0.id == id })
|
!unloaded.contains(id) || statuses.contains(where: { $0.id == id })
|
||||||
}
|
}
|
||||||
|
|
||||||
let crumb2 = Breadcrumb(level: .info, category: "TimelineViewController")
|
{
|
||||||
crumb2.message = "Filtered position statusIDs"
|
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
crumb2.data = [
|
crumb.message = "Filtered position statusIDs"
|
||||||
|
crumb.data = [
|
||||||
"statusIDs": position.statusIDs,
|
"statusIDs": position.statusIDs,
|
||||||
]
|
]
|
||||||
SentrySDK.addBreadcrumb(crumb: crumb2)
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
|
}()
|
||||||
|
|
||||||
return !position.statusIDs.isEmpty
|
return !position.statusIDs.isEmpty
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ protocol SegmentedPageViewControllerPage: Hashable {
|
||||||
var segmentedControlTitle: String { get }
|
var segmentedControlTitle: String { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPageViewController, UIPageViewControllerDelegate, TabbedPageViewController {
|
class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIViewController, UIPageViewControllerDelegate, TabbedPageViewController {
|
||||||
|
|
||||||
private(set) var pages: [Page]!
|
private(set) var pages: [Page]!
|
||||||
private let pageProvider: (Page) -> UIViewController
|
private let pageProvider: (Page) -> UIViewController
|
||||||
|
@ -23,9 +23,7 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
||||||
var currentIndex: Int! {
|
var currentIndex: Int! {
|
||||||
pages.firstIndex(of: currentPage)
|
pages.firstIndex(of: currentPage)
|
||||||
}
|
}
|
||||||
var currentViewController: UIViewController! {
|
var currentViewController: UIViewController!
|
||||||
viewControllers?.first
|
|
||||||
}
|
|
||||||
|
|
||||||
let segmentedControl = ScrollingSegmentedControl<Page>()
|
let segmentedControl = ScrollingSegmentedControl<Page>()
|
||||||
|
|
||||||
|
@ -37,7 +35,7 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
||||||
initialPage = pages.first!
|
initialPage = pages.first!
|
||||||
currentPage = pages.first!
|
currentPage = pages.first!
|
||||||
|
|
||||||
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
setPages(pages, animated: false)
|
setPages(pages, animated: false)
|
||||||
|
|
||||||
|
@ -104,12 +102,12 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
||||||
initialPage = page
|
initialPage = page
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let direction: UIPageViewController.NavigationDirection
|
let direction: AnimationMode
|
||||||
if let prevIndex = currentIndex {
|
if let prevIndex = currentIndex {
|
||||||
let index = pages.firstIndex(of: page)!
|
let index = pages.firstIndex(of: page)!
|
||||||
direction = index - prevIndex > 0 ? .forward : .reverse
|
direction = index - prevIndex > 0 ? .forward : .reverse
|
||||||
} else {
|
} else {
|
||||||
direction = .forward
|
direction = .none
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPage = page
|
currentPage = page
|
||||||
|
@ -121,12 +119,40 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
||||||
pageControllers[page] = newController
|
pageControllers[page] = newController
|
||||||
}
|
}
|
||||||
|
|
||||||
setViewControllers([newController], direction: direction, animated: animated)
|
setViewController(newController, animated: animated ? direction : .none)
|
||||||
navigationItem.title = newController.title
|
navigationItem.title = newController.title
|
||||||
|
|
||||||
segmentedControl.setSelectedOption(page, animated: animated)
|
segmentedControl.setSelectedOption(page, animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func setViewController(_ newViewController: UIViewController, animated: AnimationMode) {
|
||||||
|
guard let currentViewController,
|
||||||
|
animated != .none else {
|
||||||
|
currentViewController?.removeViewAndController()
|
||||||
|
newViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
embedChild(newViewController)
|
||||||
|
self.currentViewController = newViewController
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard currentViewController !== newViewController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.currentViewController = newViewController
|
||||||
|
newViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
embedChild(newViewController)
|
||||||
|
let direction: CGFloat = animated == .forward ? 1 : -1
|
||||||
|
newViewController.view.transform = CGAffineTransform(translationX: direction * view.bounds.width, y: 0)
|
||||||
|
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UISpringTimingParameters(dampingRatio: 1, initialVelocity: .zero))
|
||||||
|
animator.addAnimations {
|
||||||
|
newViewController.view.transform = .identity
|
||||||
|
currentViewController.view.transform = CGAffineTransform(translationX: -1 * direction * self.view.bounds.width, y: 0)
|
||||||
|
}
|
||||||
|
animator.addCompletion { _ in
|
||||||
|
currentViewController.removeViewAndController()
|
||||||
|
}
|
||||||
|
animator.startAnimation()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: TabbedPageViewController
|
// MARK: TabbedPageViewController
|
||||||
|
|
||||||
func selectNextPage() {
|
func selectNextPage() {
|
||||||
|
@ -138,7 +164,14 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
||||||
guard currentIndex > 0 else { return }
|
guard currentIndex > 0 else { return }
|
||||||
selectPage(pages[currentIndex - 1], animated: true)
|
selectPage(pages[currentIndex - 1], animated: true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SegmentedPageViewController {
|
||||||
|
enum AnimationMode: Equatable {
|
||||||
|
case none
|
||||||
|
case forward
|
||||||
|
case reverse
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SegmentedPageViewController: TabBarScrollableViewController {
|
extension SegmentedPageViewController: TabBarScrollableViewController {
|
||||||
|
|
|
@ -495,8 +495,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
filteredLabel.removeFromSuperview()
|
filteredLabel.removeFromSuperview()
|
||||||
contentView.addSubview(statusContainer)
|
contentView.addSubview(statusContainer)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
statusContainer.leadingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.leadingAnchor : contentView.leadingAnchor),
|
statusContainer.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||||
statusContainer.trailingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.trailingAnchor : contentView.trailingAnchor),
|
statusContainer.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||||
statusContainer.topAnchor.constraint(equalTo: contentView.topAnchor),
|
statusContainer.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||||
statusContainer.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
statusContainer.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||||
])
|
])
|
||||||
|
@ -506,8 +506,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
||||||
statusContainer.removeFromSuperview()
|
statusContainer.removeFromSuperview()
|
||||||
contentView.addSubview(filteredLabel)
|
contentView.addSubview(filteredLabel)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
filteredLabel.leadingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.leadingAnchor : contentView.leadingAnchor),
|
filteredLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||||
filteredLabel.trailingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.trailingAnchor : contentView.trailingAnchor),
|
filteredLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||||
filteredLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1),
|
filteredLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1),
|
||||||
contentView.bottomAnchor.constraint(equalToSystemSpacingBelow: filteredLabel.bottomAnchor, multiplier: 1),
|
contentView.bottomAnchor.constraint(equalToSystemSpacingBelow: filteredLabel.bottomAnchor, multiplier: 1),
|
||||||
])
|
])
|
||||||
|
|
Loading…
Reference in New Issue