Full screen cover is not presented correctly #2414
-
DescriptionPresenting a full screen cover after a sheet is presented and dismissed is not showing the full screen cover in full screen. Demo videoDemo projectCodeRootFeaturestruct RootFeature: Reducer {
struct Destination: Reducer {
enum State: Equatable {
case sheet(SheetFeature.State)
case fullScreenCover(FullScreenCoverFeature.State)
}
enum Action {
case sheet(SheetFeature.Action)
case fullScreenCover(FullScreenCoverFeature.Action)
}
var body: some ReducerOf<Self> {
Scope(state: /State.sheet, action: /Action.sheet, child: SheetFeature.init)
Scope(state: /State.fullScreenCover, action: /Action.fullScreenCover, child: FullScreenCoverFeature.init)
}
}
struct State: Equatable {
@PresentationState var destination: Destination.State?
}
enum Action {
case presentSheet
case destination(PresentationAction<Destination.Action>)
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .presentSheet:
state.destination = .sheet(SheetFeature.State())
return .none
case .destination(.presented(.sheet(.dismissButtonTapped))):
state.destination = .fullScreenCover(FullScreenCoverFeature.State())
return .none
case .destination:
return .none
}
}
.ifLet(\.$destination, action: /Action.destination, destination: Destination.init)
}
} struct RootView: View {
let store: StoreOf<RootFeature>
var body: some View {
VStack(alignment: .center) {
Text("Root")
Button("Show sheet") {
store.send(.presentSheet)
}
}
.sheet(
store: store.scope(state: \.$destination, action: RootFeature.Action.destination),
state: /RootFeature.Destination.State.sheet,
action: RootFeature.Destination.Action.sheet,
content: SheetView.init
)
.fullScreenCover(
store: store.scope(state: \.$destination, action: RootFeature.Action.destination),
state: /RootFeature.Destination.State.fullScreenCover,
action: RootFeature.Destination.Action.fullScreenCover,
content: FullScreenCoverView.init
)
}
} SheetFeaturestruct SheetFeature: Reducer {
@Dependency(\.dismiss) private var dismiss
struct State: Equatable {}
enum Action {
case dismissButtonTapped
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .dismissButtonTapped:
return .run { _ in await dismiss() }
}
}
}
} FullScreenCoverFeaturestruct FullScreenCoverFeature: Reducer {
@Dependency(\.dismiss) private var dismiss
struct State: Equatable {}
enum Action {
case dismissButtonTapped
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .dismissButtonTapped:
return .run { _ in await dismiss() }
}
}
}
} Checklist
Expected behaviorI would expect the full screen cover to be always presented as a full screen cover. Actual behaviorThe full screen cover is presented as a regular sheet. Steps to reproducePresent a The Composable Architecture version information1.2.0 Destination operating systemiOS 16 Xcode version informationXcode 14.3.1 Swift Compiler version informationNo response |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 8 replies
-
@omaralbeik If I run the project on iOS 17 / Xcode 15 beta 7 it works as expected, which makes me believe this is a SwiftUI bug that is reproducible in vanilla SwiftUI on iOS 16 / Xcode 14. These kinds of bugs involving multiple SwiftUI presentations swapping at the same time are generally SwiftUI bugs/limitations and require more general workarounds depending on your needs. Because of this I'm going to covert this to a discussion, but if you can demonstrate that there's a bug in our library that does not affect a similar vanilla SwiftUI project we'll definitely do our best to fix it! |
Beta Was this translation helpful? Give feedback.
-
Not sure if this is feasible in the context of TCA, but a better solution in vanilla SwiftUI is to use the |
Beta Was this translation helpful? Give feedback.
One thought would be to delay the presentation of the full screen cover about 0.3 seconds after the dismissal of the cover, that should give older versions of SwiftUI enough time to manage these presentations a bit better.