Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions Example/ExampleCardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ class ExampleCardViewController: TGCardViewController {

navigationButtonsAreSpringLoaded = true

// Pass `-classicCards` as a launch argument to compare with the classic
// presentation, where the cards aren't in a system sheet.
if ProcessInfo.processInfo.arguments.contains("-classicCards") {
presentationStyle = .classic
}

#if targetEnvironment(macCatalyst)
mode = .sidebar
#endif
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Provides a card-based view controller for mapping applications where the card's

### System sheets on iOS 27+

By default (`presentationStyle = .automatic`), on iOS 27 and later the cards are shown in a system sheet (`UISheetPresentationController`). The sheet adapts to the size classes by itself, like Maps':
On iOS 27 and later, the cards are shown in a system sheet (`UISheetPresentationController`). The sheet adapts to the size classes by itself, like Maps':

| | Presentation |
|---|---|
Expand All @@ -84,7 +84,7 @@ By default (`presentationStyle = .automatic`), on iOS 27 and later the cards are
| The card controller is itself presented, but not full screen | Classic |
| iOS 26 and earlier, or built with Xcode 26 and earlier | Classic |

Set `presentationStyle` to `.classic` to opt out. Check `usesSystemSheet` for what's currently in use.
This can't be turned off: `presentationStyle` and its `.classic` option are deprecated on iOS 27, and will be removed once that's the minimum. Check `usesSystemSheet` for what's currently in use.

Cards, map managers, headers, map buttons and paging work the same in both. Differences with a system sheet:

Expand Down
33 changes: 19 additions & 14 deletions Sources/TGCardViewController/TGCardViewController+SystemSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ extension TGCardViewController {

/// The card controller positions the cards itself, and they're dragged using
/// its own gestures.
///
/// Has no effect on iOS 27 and later, where cards always show in a system
/// sheet. On earlier versions, ``automatic`` does the same.
@available(iOS, deprecated: 27.0, message: "Cards always show in a system sheet on iOS 27 and later; earlier versions use the classic presentation anyway.")
case classic
}

Expand Down Expand Up @@ -72,7 +76,6 @@ extension TGCardViewController {
#if compiler(>=6.4) && os(iOS) && !targetEnvironment(macCatalyst) // Xcode 27 proxy, for the sheet placement API
guard
#available(iOS 27.0, *),
presentationStyle == .automatic,
mode == .floating
else { return false }

Expand Down Expand Up @@ -124,35 +127,38 @@ extension TGCardViewController {
installSystemSheet()
} else if !wantsSheet, sheetHost != nil {
uninstallSystemSheet(animated: topCardView == nil && isVisible)
} else if !wantsSheet, isAwaitingSystemSheet {
revealClassicCards()
}
}

private func revealClassicCards() {
guard isAwaitingSystemSheet else { return }
isAwaitingSystemSheet = false
toggleCardWrappers(hide: topCardView == nil)
}

}

// MARK: - Installing and removing the sheet

extension TGCardViewController {

private func installSystemSheet() {
// Can't present while a transition is under way, e.g., when this got
// pushed onto a navigation stack, as `viewDidAppear` gets called before
// that transition fully completes. Keep the cards hidden and try again
// right after it, rather than showing them the classic way.
if let coordinator = transitionCoordinator {
coordinator.animate(alongsideTransition: nil) { [weak self] _ in
DispatchQueue.main.async {
self?.updateSystemSheetPresentation()
}
}
return
}

guard
isVisible,
view.window != nil,
presentedViewController == nil,
transitionCoordinator == nil,
let content = cardWrapperContent
else {
// We'll try again later, e.g., after the presented view controller got
// dismissed. Until then, show the cards in the classic way, as we don't
// know when that'll be.
revealClassicCards()
// dismissed. Until then, the cards stay hidden, as they never show the
// classic way when we want a sheet.
return
}

Expand Down Expand Up @@ -191,7 +197,6 @@ extension TGCardViewController {

// 2. Configure the sheet
sheetHost = host
isAwaitingSystemSheet = false

#if !os(visionOS) // No detents on visionOS, where cards never use a sheet
if let sheet = host.sheetPresentationController {
Expand Down
17 changes: 7 additions & 10 deletions Sources/TGCardViewController/TGCardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ open class TGCardViewController: UIViewController {
/// uses system sheets on iOS 27+. Check ``usesSystemSheet`` for what's
/// currently used.
///
/// - Warning: Set before `viewDidLoad` is called.
/// - Note: Has no effect: cards always show in a system sheet on iOS 27 and
/// later, and the classic way before.
@available(iOS, deprecated: 27.0, message: "Cards always show in a system sheet on iOS 27 and later; earlier versions use the classic presentation anyway.")
public var presentationStyle: PresentationStyle = .automatic

// MARK: System sheet state, see `TGCardViewController+SystemSheet.swift`
Expand Down Expand Up @@ -183,10 +185,6 @@ open class TGCardViewController: UIViewController {
var sheetTargetPosition: TGCardPosition?
var isSheetDraggingEnabled = true

/// Set while the initial cards wait for the sheet, so that they don't flash up
/// in the classic presentation first
var isAwaitingSystemSheet = false

/// Set while pushing or popping, which update the sheet in one go
var isTransitioningCards = false

Expand Down Expand Up @@ -728,9 +726,7 @@ open class TGCardViewController: UIViewController {
didAddInitialCards = true

// These get pushed the classic way and move into the sheet once we've
// appeared. Keep them hidden until then.
isAwaitingSystemSheet = wantsSystemSheet

// appeared. They're hidden until then, see `toggleCardWrappers`.
initialCards.forEach { push($0, animated: false, allowToNotify: $0 == initialCards.last, completionHandler: nil) }
}

Expand Down Expand Up @@ -900,8 +896,9 @@ open class TGCardViewController: UIViewController {
} else {
sidebarBackground.alpha = 0
}
// With a system sheet, the card wrapper is just an invisible placeholder
cardWrapperShadow.alpha = hide || usesSystemSheet || isAwaitingSystemSheet ? 0 : 1
// With a system sheet, the card wrapper is just an invisible placeholder,
// and it stays invisible while waiting for the sheet to be presented
cardWrapperShadow.alpha = hide || usesSystemSheet || wantsSystemSheet ? 0 : 1

if !prepareOnly {
if mode == .sidebar {
Expand Down
Loading