SwiftUI open ShareLink from ActionSheet (confirmationDialog) Not Working - swiftui

I have a ShareLink inside an ActionSheet (confirmationDialog) but it's not opening. Can anyone confirm if this is possible or not? I imagine it's something to do with the action sheet being dismissed at the same time.
.confirmationDialog("", isPresented: $isShowingMoreActionSheet, titleVisibility: .hidden) {
if let url = URL(string: "https://www.google.com") {
ShareLink("Share", item: url)
}
}

Related

SwiftUI app - Login persistence code changes - navigation link not working after userDefault code change

In our current swiftUI app, if user closes the app they will be asked to login again - we are trying to change this behaviour by using userDefaults.
Without userDefaults code changes below LoginView directs to the home screen after login/registration using the Navigation link.
Issue:
We made below code changes to the View and LoginViewModel and when login / register button is pressed the LoginView is not taking to the home screen. It just shows the login/signup page with the login successful or registration successful message.
I have debugged in Xcode and loginOrSignUpSuccessful variable value is set to true after login button press.
Why is navigationlink not directing to MainLandingTabView Screen after login or registration?
Code Changes made to the LoginViewModel
Variable & View Code Snippet
#Published var loginOrSignUpSuccessful = UserDefaults.standard.bool(forKey: "loginOrSignUpSuccessful")
{ didSet{ UserDefaults.standard.set(self.loginOrSignUpSuccessful, forKey:"loginOrSignUpSuccessful") } }
self.loginOrSignUpSuccessful = true
UserDefaults.standard.set(true, forKey: "loginOrSignUpSuccessful")
View Code Snippet:
struct SignUpLogin: View {
private var showMainLandingTabViewLink: some View
{
NavigationLink(destination: MainLandingTabView().environmentObject(signupLoginViewModelStateObject).navigationBarBackButtonHidden(true), isActive: $signupLoginViewModelStateObject.loginOrSignUpSuccessful, label: {EmptyView()})
}
var body: some View
{
NavigationView {
ZStack(alignment: .leading) { // all the email & password, button fields.
}
.background(showMainLandingTabViewLink)
}
.environmentObject(signupLoginViewModelStateObject) .navigationBarHidden(true)
// Used to hide the back buttom if coming from NavigationView
}

How can I present an Alert programmatically Swift 5, SwiftUI in 2022

I'm looking to show an Alert without needing to press a button, i.e. programmatically. In Swift 5 / SwiftUI in 2022.
Searching has shown me this
let alert = UIAlertController(title: "alert", message: "message", preferredStyle: UIAlertController.Style.alert)
self.present(alert, animated: true, completion: nil)
When trying the above code it has issue with the nil in the completion block, but when changing it to curlys it says the view file doesn't have present. Looks to not be for SwiftUI.
How can I show an Alert in Swift 5/SwiftUI without needing a button press?
Following this Link I was able to get the following code working
struct ContentView: View {
// pass this var as binding to other views
#State var showAlert = false
func notificationReminder() -> Alert {
Alert(
title: Text("Notifications Required"),
message: Text("Please authorize notifications by going to Settings > Notifications > Remindr"),
dismissButton: .default(Text("Okay")))
}
var body: some View {
VStack {
Text("this is my main view")
}
.alert(isPresented: self.$showAlert,
content: { self.notificationReminder() })
}
}
using code I then flipped showAlert

SwiftUI: use Link with onTapGesture

I want to specify a Link in my SwiftUI view, but I also want to register when/if that Link was actually tapped or not. What's the best way to do this? I tried adding an onTapGesture on the Link (which is a View I believe):
Link("Test", destination: URL(string: "testThreePanel://")!)
.onTapGesture {
print("Testing button link tapped")
}
But the onTapGesture doesn't get invoked on tapping the link.
Is there another way to do this?
you could try this, works for me, but only on iOS15 / macOS12:
// iOS15 / macOS12 only
Link("Test", destination: URL(string: "https://duckduckgo.com")!)
.environment(\.openURL, OpenURLAction { url in
print("---> testing link actioned")
return .systemAction
})
Just enable firing both embedded and added gestures simultaneously.
struct ContentView: View {
var body: some View {
Link("Test", destination: URL(string: "testThreePanel://")!)
.simultaneousGesture(
TapGesture()
.onEnded { val in
print("Testing button link tapped \(val)")
}
)
}
}
For iOS 15 it also works if you remove the 'url' parameter, just in case you don't want to use it.
Link("Test", destination: URL(string: "https://duckduckgo.com")!)
.environment(\.openURL, OpenURLAction { _ in
print("---> testing link actioned")
return .systemAction
})

NavigationLink doesn't fire after FullScreenCover is dismissed

I have a button in a view (inside a NavigationView) that opens a full screen cover - a loading screen while some data is processing. When the cover is dismissed, I want to automatically route to the next view programmatically. I'm using a NavigationLink with a tag and selection binding, and the binding value updates when the cover is dismissed, but the routing doesn't happen unless I tap that same "open modal" button again.
import SwiftUI
struct OpenerView: View {
#EnvironmentObject var viewModel: OpenerViewModel
#State private var selection: Int? = nil
#State private var presentLoadingScreen = false
var body: some View {
VStack {
NavigationLink(destination: SecondScreen(), tag: 1, selection: $selection) { EmptyView() }
Button(action: {
viewModel.frequency = 0
self.presentLoadingScreen.toggle()
}, label: {
Text("Open cover")
}).buttonStyle(PlainButtonStyle())
}
.navigationBarTitle("Nav title", displayMode: .inline)
.fullScreenCover(isPresented: $presentLoadingScreen, onDismiss: {
self.selection = 1
}, content: ModalView.init)
}
}
struct ModalView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
Text("Howdy")
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
presentationMode.wrappedValue.dismiss()
}
}
}
}
The first time I hit the Button, the cover opens. Inside the cover is just a DispatchQueue.main.asyncAfter which dismisses it after 2 seconds. When it's dismissed, the onDismiss fires, but then I have to hit the button again to route to SecondScreen.
Any ideas?
Edit: Added the modal's View
I got it working with some changes to the code, and I'm sharing here along with what I think is happening.
I believe the problem is a race condition using a #State boolean to toggle the cover and the navigation. When the cover is being dismissed, my main OpenerView is being recreated - to be expected with state changes. Because of this, I try to set the #State var selection to trigger the navigation change, but before it can do so, the view is recreated with selection = nil.
There seem to be two ways to solve it in my case:
Move the cover boolean to my view model - this worked, but I didn't want it there because it only applied to this view and it's a shared view model for this user flow. Plus, when the modal is dismissed, you see the current OpenerView for a brief flash and then get routed to the SecondScreen.
Keep the cover boolean in #State, but trigger the navigation change in the button immediately after setting the boolean to open the modal. This worked better for my use case because the modal opens, and when it closes, the user is already on the next screen.
I had a similar problem where I was trying to draw a view after dismissing a fullScreenCover. I kept getting an error that said that the view had been deallocated since it was trying to draw to the fullScreenCover.
I used Joe's hints above to make this work. Specifically:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
viewToShow()
}
I had previously tried onChange, onDisappear, onAppear - but none of those fit the use case I needed.

Adding a URL within a Text object in Swift

I am battling with layout or padding or something similar in SwiftUI.
What I want is a view containing a sentence that reads "A website named StackOverflow exists for peer help" where StackOverflow is a URL that the user may tap and navigate to the StackOverflow website. The code below works however ...... the button with the link appears out of line. I want it to read like a sentence without line breaks or padding etc.
All ideas welcome, but it is not as simple as embedding in an HStack.
var body: some View {
Form {
Section(header: Text("something)")) {
let urlStackOverflow: URL = URL(string: "https://www.stackoverflow.com“)!
Text("A website named")
Button(action: { UIApplication.shared.open(urlStackOverflow) }, label: {
Text("StackOverflow“).bold()
})
Text("exists for peer help“)
}}}
Here's a solution with a single Button and multiple Texts added together as views.
struct ContentView: View {
let urlStackOverflow = URL(string: "https://www.stackoverflow.com")!
var body: some View {
Form {
Section(header: Text("something")) {
Button(action: { UIApplication.shared.open(self.urlStackOverflow) }) {
Text("A website named")
+ Text(" StackOverflow ")
.bold()
.foregroundColor(Color.blue)
+ Text("exists for peer help.")
}
.foregroundColor(Color.black)
}
}
}
}
Limitations:
The entire text would be clickable.
Multiple links are not supported.