Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A ToastUI triggering while a SwiftUI Menu is active can sometimes later cause sheets to fail to open. #21

Closed
2 tasks done
JonnyReinEriksen opened this issue Jul 9, 2021 · 7 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@JonnyReinEriksen
Copy link

JonnyReinEriksen commented Jul 9, 2021

Pre-requisites:

  • Yes, I looked through both open and closed issues looking for what I needed.
  • No, I did not find what I was looking for.

Expected Behavior

Current Behavior

Possible Solution

A workaround is to use .contextMenu instead of Menu.

Steps to Reproduce

With this activated:
Menu {
Button() {
UIPasteboard.general.string = selectedText
} label: {
Image(systemName: "doc.on.doc")
Text("Copy")
}
}
label:
{
Image(systemName: "ellipsis")
.imageScale(.large)
.padding()
}

And concurrently triggering a Toast:
.toast(isPresented: $isLocked) {
LockScreen()
}

And then later calling sheet(), for instance:
.sheet(isPresented: $showQRCode) {
QRCode(showQRCode: self.$showQRCode)
}
Will generate the following error:

2021-07-09 23:21:11.290959+0200 AppName[10762:4800555] [Presentation] Attempt to present <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x113507a20> on <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x111d08800> (from <TtGC7SwiftUI19UIHostingControllerVS_14_ViewList_View: 0x111d2ca80>) which is already presenting <_UIContextMenuActionsOnlyViewController: 0x1137095f0>.

Context

I am using Toast to present a LockScreen that triggers when moving an app to the background.
It works great with all other kinds of dialogs, like sheets or contextMenus, but using Menu causes the above issue.

I am using XCode 12.5.1
iOS 14.6,
iPhone 12 Pro Max

@JonnyReinEriksen JonnyReinEriksen added bug Something isn't working help wanted Extra attention is needed labels Jul 9, 2021
@quanshousio
Copy link
Owner

Can you provide a minimal reproducible example of your bug here? I attach .toast modifier on Menu, tried to replicate your usage context but there is no error. Are you sure there is no other presented view (e.g. QRCode) when presenting the toast?

Here's my full example for reference.

struct ContentView: View {
  @State var selectedText: String = ""
  @State var showQRCode: Bool = false
  @State var isLocked: Bool = false

  var body: some View {
    TextField("TextField", text: $selectedText)
    Menu {
      Button {
        UIPasteboard.general.string = selectedText
      } label: {
        Label("Copy", systemImage: "doc.on.doc")
      }
    } label: {
      Image(systemName: "ellipsis")
        .imageScale(.large)
        .padding()
    }
    .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
      isLocked = true
    }
    .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
      isLocked = false
    }
    .toast(isPresented: $isLocked) {
      ToastView("Screen is locked")
    }
    .sheet(isPresented: $showQRCode) {
      Text("QR Code")
    }
  }
}

@JonnyReinEriksen
Copy link
Author

Thank you for looking at this. The code:

ToastDemoapp.swift:
import SwiftUI

@main
struct ToastDemoApp: App {
    @Environment(\.scenePhase) var scenePhase
    @State var showToast = false
    var body: some Scene {
        WindowGroup {
            ContentView()
                .toast(isPresented: $showToast) {
                    LockScreen()
                }
                .onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
                    showToast = false
                }
                .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
                    showToast = true
                }
                .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
                    showToast = true
                }
        }
    }
}

ContentView.swift:

//
// ContentView.swift
// ToastDemo
//
// Created by Jonny Rein Eriksen on 12/07/2021.
//

import SwiftUI
import ToastUI

struct QRCode: View {
@binding var showSheet: Bool
init(showSheet: Binding) {
self._showSheet = showSheet
}
var body: some View {
NavigationView {
Text("Test")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {self.showSheet.toggle()}, label: {
Text("Cancel")
.padding()
})
}
}
}
}
}

struct LockScreen: View {
var body: some View {
ZStack {
Color(.systemBackground).edgesIgnoringSafeArea(.all)
VStack{
Text("Locked")
.font(Font.system(size: 28, weight: .heavy))
.multilineTextAlignment(.center)
}
}
}
}

struct ContentView: View {
@State var showSheet = false
var count = 5

var body: some View {
    VStack {
        
        Menu {
            Button() {
            } label: {
                Image(systemName: "doc.on.doc")
                Text("Copy")
            }
            .disabled(count == 0)
            Button() {
            } label: {
                Text("Show")
                Image(systemName: "eye")
            }
            .disabled(count == 5)
            Button() {
            } label: {
                Text("View")
                Image(systemName: "doc.text.magnifyingglass")
            }
            Button() {
            } label: {
                Image(systemName: "square.and.pencil")
                Text("Edit")
            }
            Divider()
            Button(/*role: .destructive*/) {
            } label: {
                Image(systemName: "trash")
                Text("Delete")
            }


        }
            label:
        {
            Image(systemName: "ellipsis")
                .imageScale(.large)
                .padding()
        }
        
        Button(action: {self.showSheet.toggle()}, label: {
            Text("Show Sheet")
        })
        .sheet(isPresented: $showSheet) {
            QRCode(showSheet: self.$showSheet)
        }
    }
}

}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Reproduction procedure:

  1. open menu by touching "..."
  2. While menu displays drag from bottom of screen until Lock/toast appears, then quickly drag down again or slowly moving up so toast disappears. Repeat until also menu disappears (It is very timing-sensitive). Multiple patterns seem to lead to this state.
  3. If menu has disappeared touch "Show sheet". If reproduction succeeds instead of sheet displaying you will get:

2021-07-13 01:13:04.253733+0200 ToastDemo[11444:184732] [Presentation] Attempt to present <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x7fddfb034aa0> on <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x7fddf9607ca0> (from <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x7fddf9607ca0>) which is already presenting <_UIContextMenuActionsOnlyViewController: 0x7fddfb021d30>.

I can reproduce both on device and in simulator with the above code.

@quanshousio
Copy link
Owner

I'm able to reproduce the error, albeit a little bit difficult as it is a race condition bug. Upon investigation, I also found other bugs related to handling the view presentation, such as the toast might not be shown if the binding changes during the presentation. In your case, it would result in the toast might not be shown even if the application is in the background.

Thanks for your report. I will release the fix soon.

@JonnyReinEriksen
Copy link
Author

Sounds promising. I also found that dismissing the view on binding changes will fail sometimes. It would be great if you would release the fix?

@quanshousio
Copy link
Owner

Quick update on this, I will release the new version when Xcode 13.0 is released. I want to test it thoroughly to make sure it works properly on the official build. Xcode 13.0 RC is weird as its SDK removes lots of new SwiftUI features that were existed in previous versions. I hope this is just a temporary issue.

This was referenced Apr 11, 2022
@quanshousio
Copy link
Owner

quanshousio commented Apr 11, 2022

My apologies for delays. I fixed the issue in the latest 3.0.0 version. Would you mind checking that for me? Let me know if you encounter any issues.

@JonnyReinEriksen
Copy link
Author

Verified fixed with 3.0.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants