Compare commits
8 Commits
566df3e285
...
5029b26b40
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 5029b26b40 | |
Shadowfacts | 907cf08400 | |
Shadowfacts | e85d194e5f | |
Shadowfacts | cfeb87d2ba | |
Shadowfacts | e4f3735c9f | |
Shadowfacts | baa9dfe0f1 | |
Shadowfacts | 5e73439e7b | |
Shadowfacts | 4b2776ee81 |
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## 2023.1 (63)
|
||||
Bugfixes:
|
||||
- Fix status cells being inset too much on iPhones
|
||||
- Fix more things not adjusting to accent color preference
|
||||
- Fix various views not being keyboard focusable
|
||||
- Add more logging around state restoartion crash
|
||||
|
||||
## 2023.1 (62)
|
||||
Features/Improvements:
|
||||
- Add New List action in Add to List menu
|
||||
|
|
|
@ -2314,7 +2314,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 62;
|
||||
CURRENT_PROJECT_VERSION = 63;
|
||||
INFOPLIST_FILE = Tusker/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
|
@ -2382,7 +2382,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 62;
|
||||
CURRENT_PROJECT_VERSION = 63;
|
||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
||||
|
@ -2533,7 +2533,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 62;
|
||||
CURRENT_PROJECT_VERSION = 63;
|
||||
INFOPLIST_FILE = Tusker/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
|
@ -2562,7 +2562,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Tusker/Tusker.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 62;
|
||||
CURRENT_PROJECT_VERSION = 63;
|
||||
INFOPLIST_FILE = Tusker/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
|
@ -2672,7 +2672,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 62;
|
||||
CURRENT_PROJECT_VERSION = 63;
|
||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
||||
|
@ -2698,7 +2698,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = OpenInTusker/OpenInTusker.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 62;
|
||||
CURRENT_PROJECT_VERSION = 63;
|
||||
INFOPLIST_FILE = OpenInTusker/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.3;
|
||||
|
|
|
@ -88,6 +88,10 @@
|
|||
argument = "-com.apple.CoreData.ConcurrencyDebug 1"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-UIFocusLoggingEnabled YES"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "-UIFocusLoopDebuggerEnabled YES"
|
||||
isEnabled = "YES">
|
||||
|
|
|
@ -36,6 +36,7 @@ class AccountListViewController: UIViewController, CollectionViewController {
|
|||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
dataSource = createDataSource()
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ class AssetCollectionViewController: UIViewController, UICollectionViewDelegate
|
|||
collectionView.alwaysBounceVertical = true
|
||||
collectionView.allowsMultipleSelection = true
|
||||
collectionView.allowsSelection = true
|
||||
collectionView.allowsFocus = true
|
||||
|
||||
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: "AlbumTableViewCell", bundle: .main), forCellReuseIdentifier: "albumCell")
|
||||
|
||||
tableView.allowsFocus = true
|
||||
|
||||
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
||||
switch item {
|
||||
case .cameraRoll:
|
||||
|
|
|
@ -41,6 +41,7 @@ class BookmarksTableViewController: EnhancedTableViewController {
|
|||
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 140
|
||||
tableView.allowsFocus = true
|
||||
|
||||
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell)
|
||||
|
||||
|
|
|
@ -61,13 +61,13 @@ class ConversationTableViewController: EnhancedTableViewController {
|
|||
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.prefetchDataSource = self
|
||||
|
||||
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "statusCell")
|
||||
tableView.register(UINib(nibName: "ConversationMainStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "mainStatusCell")
|
||||
tableView.register(UINib(nibName: "ExpandThreadTableViewCell", bundle: .main), forCellReuseIdentifier: "expandThreadCell")
|
||||
|
||||
tableView.prefetchDataSource = self
|
||||
|
||||
tableView.allowsFocus = true
|
||||
tableView.backgroundColor = .secondarySystemBackground
|
||||
// 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
|
||||
|
|
|
@ -26,7 +26,7 @@ class ExpandThreadTableViewCell: UITableViewCell {
|
|||
|
||||
threadLinkView = UIView()
|
||||
threadLinkView.translatesAutoresizingMaskIntoConstraints = false
|
||||
threadLinkView.backgroundColor = tintColor.withAlphaComponent(0.5)
|
||||
threadLinkView.backgroundColor = .tintColor.withAlphaComponent(0.5)
|
||||
threadLinkView.layer.cornerRadius = 2.5
|
||||
contentView.addSubview(threadLinkView)
|
||||
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">
|
||||
<rect key="frame" x="108" y="12" width="65" height="20.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" systemColor="systemBlueColor"/>
|
||||
<color key="textColor" systemColor="tintColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
|
@ -74,7 +74,7 @@
|
|||
<systemColor name="separatorColor">
|
||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBlueColor">
|
||||
<systemColor name="tintColor">
|
||||
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
|
|
|
@ -42,6 +42,7 @@ class AddSavedHashtagViewController: UIViewController {
|
|||
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
|
||||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
collectionView.delegate = self
|
||||
collectionView.allowsFocus = true
|
||||
view.addSubview(collectionView)
|
||||
|
||||
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.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
view.addSubview(collectionView)
|
||||
|
||||
dataSource = createDataSource()
|
||||
|
|
|
@ -68,6 +68,7 @@ class ProfileDirectoryViewController: UIViewController {
|
|||
collectionView.register(UINib(nibName: "FeaturedProfileCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "featuredProfileCell")
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
view.addSubview(collectionView)
|
||||
|
||||
dataSource = createDataSource()
|
||||
|
|
|
@ -40,6 +40,7 @@ class TrendingHashtagsViewController: UIViewController {
|
|||
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
view.addSubview(collectionView)
|
||||
|
||||
let registration = UICollectionView.CellRegistration<TrendingHashtagCollectionViewCell, Hashtag> { cell, indexPath, hashtag in
|
||||
|
|
|
@ -36,6 +36,7 @@ class TrendingLinksViewController: EnhancedTableViewController {
|
|||
|
||||
tableView.register(TrendingLinkTableViewCell.self, forCellReuseIdentifier: "trendingLinkCell")
|
||||
tableView.estimatedRowHeight = 100
|
||||
tableView.allowsFocus = true
|
||||
|
||||
dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { tableView, indexPath, item in
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: "trendingLinkCell", for: indexPath) as! TrendingLinkTableViewCell
|
||||
|
|
|
@ -62,12 +62,15 @@ class TrendingStatusesViewController: UIViewController {
|
|||
}
|
||||
let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
|
||||
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
||||
section.contentInsetsReference = .readableContent
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
section.contentInsetsReference = .readableContent
|
||||
}
|
||||
return section
|
||||
}
|
||||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
|
||||
dataSource = createDataSource()
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ class EditListAccountsViewController: EnhancedTableViewController {
|
|||
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 66
|
||||
tableView.allowsSelection = false
|
||||
|
||||
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
||||
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: "StatusUpdatedNotificationTableViewCell", bundle: .main), forCellReuseIdentifier: updatedCell)
|
||||
tableView.register(UINib(nibName: "BasicTableViewCell", bundle: .main), forCellReuseIdentifier: unknownCell)
|
||||
|
||||
tableView.cellLayoutMarginsFollowReadableWidth = true
|
||||
tableView.allowsFocus = true
|
||||
}
|
||||
|
||||
private func request(range: RequestRange) -> Request<[Pachyderm.Notification]> {
|
||||
|
|
|
@ -85,13 +85,16 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie
|
|||
return .list(using: .init(appearance: .plain), layoutEnvironment: environment)
|
||||
} else {
|
||||
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
||||
section.contentInsetsReference = .readableContent
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
section.contentInsetsReference = .readableContent
|
||||
}
|
||||
return section
|
||||
}
|
||||
}
|
||||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
|
||||
registerTimelineLikeCells()
|
||||
dataSource = createDataSource()
|
||||
|
@ -553,6 +556,15 @@ extension ProfileStatusesViewController: UICollectionViewDelegate {
|
|||
func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
|
||||
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 {
|
||||
|
|
|
@ -83,6 +83,8 @@ class SearchResultsViewController: EnhancedTableViewController {
|
|||
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell)
|
||||
tableView.register(UINib(nibName: "HashtagTableViewCell", bundle: .main), forCellReuseIdentifier: hashtagCell)
|
||||
|
||||
tableView.allowsFocus = true
|
||||
|
||||
dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in
|
||||
switch item {
|
||||
case let .account(id):
|
||||
|
|
|
@ -70,6 +70,7 @@ class SearchViewController: UIViewController {
|
|||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.backgroundColor = .secondarySystemBackground
|
||||
collectionView.allowsFocus = true
|
||||
view.addSubview(collectionView)
|
||||
|
||||
dataSource = createDataSource()
|
||||
|
|
|
@ -74,6 +74,7 @@ class StatusActionAccountListViewController: UIViewController, CollectionViewCon
|
|||
view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
dataSource = createDataSource()
|
||||
}
|
||||
|
||||
|
|
|
@ -90,12 +90,15 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
// just setting layout.configuration.contentInsetsReference doesn't work with UICollectionViewCompositionalLayout.list
|
||||
let layout = UICollectionViewCompositionalLayout { sectionIndex, environment in
|
||||
let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment)
|
||||
section.contentInsetsReference = .readableContent
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
section.contentInsetsReference = .readableContent
|
||||
}
|
||||
return section
|
||||
}
|
||||
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dragDelegate = self
|
||||
collectionView.allowsFocus = true
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(collectionView)
|
||||
NSLayoutConstraint.activate([
|
||||
|
@ -353,10 +356,26 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
|
||||
@MainActor
|
||||
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 })
|
||||
guard !unloaded.isEmpty else {
|
||||
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
|
||||
for id in unloaded {
|
||||
group.addTask {
|
||||
|
@ -377,6 +396,9 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
switch result {
|
||||
case .success(let status):
|
||||
statuses.append(status)
|
||||
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||
crumb.message = "Loaded status \(id)"
|
||||
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||
case .failure(let error):
|
||||
let crumb = Breadcrumb(level: .error, category: "TimelineViewController")
|
||||
crumb.message = "Error loading status"
|
||||
|
@ -389,12 +411,14 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
}
|
||||
await mastodonController.persistentContainer.addAll(statuses: statuses, in: mastodonController.persistentContainer.viewContext)
|
||||
|
||||
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||
crumb.message = "Original position statusIDs"
|
||||
crumb.data = [
|
||||
"statusIDs": position.statusIDs,
|
||||
]
|
||||
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||
_ = {
|
||||
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||
crumb.message = "Position statusIDs before filtering"
|
||||
crumb.data = [
|
||||
"statusIDs": position.statusIDs,
|
||||
]
|
||||
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||
}()
|
||||
|
||||
// update the timeline position in case some statuses couldn't be loaded
|
||||
if let center = position.centerStatusID {
|
||||
|
@ -408,12 +432,14 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
|||
!unloaded.contains(id) || statuses.contains(where: { $0.id == id })
|
||||
}
|
||||
|
||||
let crumb2 = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||
crumb2.message = "Filtered position statusIDs"
|
||||
crumb2.data = [
|
||||
"statusIDs": position.statusIDs,
|
||||
]
|
||||
SentrySDK.addBreadcrumb(crumb: crumb2)
|
||||
{
|
||||
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||
crumb.message = "Filtered position statusIDs"
|
||||
crumb.data = [
|
||||
"statusIDs": position.statusIDs,
|
||||
]
|
||||
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||
}()
|
||||
|
||||
return !position.statusIDs.isEmpty
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ protocol SegmentedPageViewControllerPage: Hashable {
|
|||
var segmentedControlTitle: String { get }
|
||||
}
|
||||
|
||||
class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPageViewController, UIPageViewControllerDelegate, TabbedPageViewController {
|
||||
class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIViewController, UIPageViewControllerDelegate, TabbedPageViewController {
|
||||
|
||||
private(set) var pages: [Page]!
|
||||
private let pageProvider: (Page) -> UIViewController
|
||||
|
@ -23,9 +23,7 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
|||
var currentIndex: Int! {
|
||||
pages.firstIndex(of: currentPage)
|
||||
}
|
||||
var currentViewController: UIViewController! {
|
||||
viewControllers?.first
|
||||
}
|
||||
var currentViewController: UIViewController!
|
||||
|
||||
let segmentedControl = ScrollingSegmentedControl<Page>()
|
||||
|
||||
|
@ -37,7 +35,7 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
|||
initialPage = pages.first!
|
||||
currentPage = pages.first!
|
||||
|
||||
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
setPages(pages, animated: false)
|
||||
|
||||
|
@ -104,12 +102,12 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
|||
initialPage = page
|
||||
return
|
||||
}
|
||||
let direction: UIPageViewController.NavigationDirection
|
||||
let direction: AnimationMode
|
||||
if let prevIndex = currentIndex {
|
||||
let index = pages.firstIndex(of: page)!
|
||||
direction = index - prevIndex > 0 ? .forward : .reverse
|
||||
} else {
|
||||
direction = .forward
|
||||
direction = .none
|
||||
}
|
||||
|
||||
currentPage = page
|
||||
|
@ -121,12 +119,40 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
|||
pageControllers[page] = newController
|
||||
}
|
||||
|
||||
setViewControllers([newController], direction: direction, animated: animated)
|
||||
setViewController(newController, animated: animated ? direction : .none)
|
||||
navigationItem.title = newController.title
|
||||
|
||||
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
|
||||
|
||||
func selectNextPage() {
|
||||
|
@ -138,7 +164,14 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIPage
|
|||
guard currentIndex > 0 else { return }
|
||||
selectPage(pages[currentIndex - 1], animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
extension SegmentedPageViewController {
|
||||
enum AnimationMode: Equatable {
|
||||
case none
|
||||
case forward
|
||||
case reverse
|
||||
}
|
||||
}
|
||||
|
||||
extension SegmentedPageViewController: TabBarScrollableViewController {
|
||||
|
|
|
@ -495,8 +495,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
|||
filteredLabel.removeFromSuperview()
|
||||
contentView.addSubview(statusContainer)
|
||||
NSLayoutConstraint.activate([
|
||||
statusContainer.leadingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.leadingAnchor : contentView.leadingAnchor),
|
||||
statusContainer.trailingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.trailingAnchor : contentView.trailingAnchor),
|
||||
statusContainer.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||
statusContainer.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||
statusContainer.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||
statusContainer.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
])
|
||||
|
@ -506,8 +506,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
|||
statusContainer.removeFromSuperview()
|
||||
contentView.addSubview(filteredLabel)
|
||||
NSLayoutConstraint.activate([
|
||||
filteredLabel.leadingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.leadingAnchor : contentView.leadingAnchor),
|
||||
filteredLabel.trailingAnchor.constraint(equalTo: UIDevice.current.userInterfaceIdiom == .pad ? contentView.readableContentGuide.trailingAnchor : contentView.trailingAnchor),
|
||||
filteredLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||
filteredLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||
filteredLabel.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1),
|
||||
contentView.bottomAnchor.constraint(equalToSystemSpacingBelow: filteredLabel.bottomAnchor, multiplier: 1),
|
||||
])
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="252" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="O0E-Vf-XYR" customClass="StatusCollapseButton" customModule="Tusker" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="49" width="295" height="30"/>
|
||||
<color key="backgroundColor" systemColor="systemBlueColor"/>
|
||||
<color key="backgroundColor" systemColor="tintColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="z84-XW-gP3"/>
|
||||
</constraints>
|
||||
|
@ -289,7 +289,7 @@
|
|||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
<systemColor name="systemBlueColor">
|
||||
<systemColor name="tintColor">
|
||||
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue