Conditionally navigate to new view in swiftui - ios

I tried to navigate to my user view in login submit function with swiftui.
struct LoginUIView: View {
...
var body: some View {
VStack {
...
Button(action: {
self.login(name: self.name, pass: self.pass)
}) {
Text("Login")
.padding()
.frame(maxWidth: .infinity)
.foregroundColor(Color.white)
.cornerRadius(4.0)
.background(Color("light-green"))
}
}
.padding()
}
func login(name: String, pass: String) {
// auth with name and pass
// then try to conditionally navigate to specific view
if ... {
// navigate to user view
}
if ... {
// navigate to other view
}
}
}

Related

Minimize or bring back sheet in SwiftUI

I have a Voip calling app using CallKit and when call received, it will open a view call IncomingView in a sheet in my SwiftUI app. So far so good. But i want to minimize the sheet and can navigate to other pages and preferably shows a green bar at the navigation (similar to WhatApp) that indicates the call is going on and when i tap there, it should bring back my "IncomingView".
here is my code:
struct MainView: View {
let acceptPublishser = NotificationCenter.default
.publisher(for: Notification.Name.DidCallAccepted)
let endPublisher = NotificationCenter.default
.publisher(for: Notification.Name.DidCallEnd)
var body: some View {
NavigationView {
TabView {
TabListView()
.tabItem {
Label("Home", systemImage: "house.fill")
}
ContactListView()
.tabItem {
Label("Contacts", systemImage: "person.crop.circle")
}
ProfileView()
.tabItem {
Label("Profile", systemImage: "person.crop.circle")
}
}
.padding(0)
.onAppear(){
self.showModal = MyCallDelegate.shared.isIncomingCall
}
.sheet(isPresented: $showModal){
IncomingCallView() // -> Present IncomingCallview() as sheet
}
.accentColor(Color(.green))
}.onReceive(self.acceptPublishser, perform: { output in
showModal = true
})
.onReceive(self.endPublisher, perform: { output in
showModal = false
})
}
}
struct IncomingCallView: View {
var body: some View {
VStack{
Spacer()
Text("callerId").foregroundColor(.white)
Text("Timer").foregroundColor(.white)
}
}

SwiftUI Button action statements

I'd like to do a statement in button block, if textfield is empty, then get an alert and you can't acces the other ViewController, if you fill he textfield, then you can start play:
LaunchView.swift :
Button(action: {
if username.isEmpty {
showingAlert = true
} else {
//Here I would like to acces another view
}
}) {
Text("PLAY")
.padding()
.foregroundColor(.black)
.frame(width: 350)
.background(Color.white)
.clipShape(Capsule())
.shadow(radius: 15)
}.alert(isPresented:$showingAlert) {
Alert(
title: Text("Error"),
message: Text("Enter your username"),
dismissButton: .cancel()
)
}
And I have one more question, how could I use a variable from LaunchView, in FirstView?
Like, I would like to get the name from LaunchView's textfield, in alerts in FirstView:
"(username), your score is X"
FirstView.swift:
.alert(isPresented: $showingScore) {
Alert(title: Text(scoreTitle), message: Text("Your score is \(point)"), dismissButton: .default(Text("Continue")) {
self.askQuestion()
})
}

SwiftUI List NavigationView onDelete alert confirmation has ugly animation

The problem is that whenever you put the list in navigationView, the animation of the delete cancelation of the list row is not so nice. Am I doing something wrong in my body property?
var body: some View {
NavigationView {
VStack {
List {
ForEach(self.contacts){ contact in
ContactRow(contact: contact)
}.onDelete { self.setDeletIndex(at: $0) }
}
.alert(isPresented: $showConfirm) {
Alert(title: Text("Delete"), message: Text("Sure?"),
primaryButton: .cancel(),
secondaryButton: .destructive(Text("Delete")) {
self.delete()
})
}
.listStyle(PlainListStyle())
.navigationTitle("Contacts")
.navigationBarItems(trailing: HStack {
Button("Add", action: self.addItem)
})
}
}
}

SwiftUI NavigationLink: how to call a function before showing destination view

I would like to call a function, after clicking on an item, and before displaying the destination view.
The code below doesn't seem to work: myFunction is called, but the destination view is not shown.
It looks like the onTapGesture overwrites the NavigationLink destination.
NavigationView {
List(restaurants) { restaurant in
NavigationLink(destination: RestaurantView(restaurant: restaurant)) {
RestaurantRow(restaurant: restaurant)
}.onTapGesture { myModel.myFunction(restaurant) }
}
}
How can I have both, when clicking on a list item?
function is called
destination view is shown
Try to add NavigationLink into a Button, like:
Button(action: {
//Call here
myModel.myFunction(restaurant)
}, label: {
NavigationLink(destination: RestaurantView(restaurant: restaurant)) {
RestaurantRow(restaurant: restaurant)
}
})
EDIT pasted test code, try directly
struct TestNavigationView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Detail").onAppear() {
test()
}) {
Text("Click")
}
}
}
}
func test() {
print("Hell0")
}
}
another approach: (might not work if List there)
struct TestNavigationView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Detail")) {
Text("Click")
}.simultaneousGesture(TapGesture().onEnded{
test()
})
}
}
}
func test() {
print("Hell0")
}
}

App freezes when I change EnvironmentObject value

I want to login my user when they click a button. When they click the button, it calls self.auth.login() which changes loggedIn to true.
When this change happens, ContentView is meant to reload with HomeView() as the body View. However it just crashes the app.
Here's my code:
ContentView.swift
struct ContentView: View {
#EnvironmentObject var settings: UserSettings
#EnvironmentObject var auth: UserAuth
var body: some View {
if (!auth.loggedIn){
return AnyView(LoginView())
} else {
return AnyView(HomeView())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(UserAuth())
}
}
class UserAuth: ObservableObject {
#Published var loggedIn: Bool = false
func login(){
self.loggedIn = true
}
}
struct LoginView: View {
#EnvironmentObject var auth: UserAuth
var body: some View {
ZStack {
Color.orange
.edgesIgnoringSafeArea(.all)
VStack {
Image("launcher_logo").resizable()
.scaledToFit()
.frame(height: 100)
.padding(.top, 100)
Spacer()
Button(action: {
self.auth.login()
print("loggedIn: ", self.auth.loggedIn) // prints "loggedIn: true" then doesn't print again when pressed
}) {
Text(String(auth.loggedIn))
}
...
Any idea what the problem is?
EDIT:
If I change my ContentView View to just LoginView() then it doesn't freeze. The app works. But I wan ContentView to be dynamic based on whether the user is loggedIn or not.
EDIT2: HomeView is causing it to crash:
struct HomeView: View {
// #EnvironmentObject var auth: UserAuth
var body: some View {
TabView {
HomeView()
.tabItem {
Image(systemName: "1.square.fill")
Text(String("4"))
}.onTapGesture {
// self.auth.login()
}
HomeView()
.tabItem {
Image(systemName: "3.square.fill")
}
Text("The Last Tab")
.tabItem {
Image(systemName: "3.square.fill")
Text("Profile")
}
}
.font(.headline)
}
func goOnline(){
print("went online")
}
}
console log:
[Firebase/Crashlytics][I-CLS000000] Failed to download settings Error Domain=FIRCLSNetworkError Code=-5 "(null)" UserInfo={status_code=404, type=2, request_id=, content_type=text/html; charset=utf-8}
2020-06-04 19:53:04.408869+1000 App[6718:4035694] Connection 5: received failure notification
2020-06-04 19:53:04.409001+1000 App[6718:4035694] Connection 5: failed to connect 3:-9816, reason -1
2020-06-04 19:53:04.409111+1000 App[6718:4035694] Connection 5: encountered error(3:-9816)
Your HomeView calls itself, causing an infinite loop.

Resources