I am new to swift (I am more used to python) and I am trying to send a POST request to a server and use the JSON response. I have been able to make the POST request and retrieve data and print it using this code that I got from a tutorial but the variable server.authenticated wasn't changing and after I made some changes now I'm getting two errors: Instance member 'authenticated' cannot be used on type 'HttpAuth' and 'String' is not convertible to 'Any'
Could someone please help?
import SwiftUI
import Combine
struct ServerMessage : Decodable {
let status, message: String
}
class HttpAuth: ObservableObject {
var didChange = PassthroughSubject<HttpAuth, Never>()
#Published var authenticated = false {
didSet{
didChange.send(self)
}
}
func checkDetails(username: String, password: String) {
guard let url = URL(string: "https://example.com") else { return }
let body: [String: String] = ["username": username, "password": password ]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
print(finalData)
if finalData.status == "ok" {
DispatchQueue.global().async {
HttpAuth.authenticated = true //ERROR: Instance member 'authenticated' cannot be used on type 'HttpAuth'
print("correct credentials")
}
}
}.resume()
}
}
struct loginView: View {
#State private var username: String = ""
#State private var password: String = ""
#State var server = HttpAuth()
var body: some View {
VStack{
TextField("Username", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width: 200, height: nil)
.multilineTextAlignment(.center)
.disableAutocorrection(true)
.accessibility(identifier: "Username")
.autocapitalization(.none)
SecureField("Password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width: 200, height: nil)
.multilineTextAlignment(.center)
.disableAutocorrection(true)
.accessibility(identifier: "Password")
Button(action: {
self.server.checkDetails(username: self.username, password: self.password)
//print(self.username + ", " + self.password)
}) {
HStack{
Spacer()
Text("Login").font(.headline).foregroundColor(.white)
Spacer()
}.padding(.vertical, 10)
.background(Color.red)
.padding(.horizontal, 40)
}
if self.server.authenticated {
Text("Correct Credentials")
} //ERROR: 'String' is not convertible to 'Any'
}
}
}
struct loginView_Previews: PreviewProvider {
static var previews: some View {
loginView()
}
}
You need to pass HttpAuth to your loginView like
struct loginView_Previews: PreviewProvider {
static var previews: some View {
loginView().environmentObject(HttpAuth())
}
}
then in your LoginView declare EnvironmentObject of HttpAuth
struct loginView: View {
#State private var username: String = ""
#State private var password: String = ""
#EnvironmentObject var server : HttpAuth
...
Related
am a beginner in swiftui, still learning how to deal with ObservableObject
let me show my code and illustrate what is my question...
JsonResponse as follows:
{
"error" : false,
"user" : {
"username" : "Maxwell",
"id" : 84560,
"name" : "Max",
"authority" : "Manager"
}
}
Authenticate User Class (ObservableObject):
import Foundation
import Alamofire
struct UserDetails{
static var id: String = ""
static var name: String = ""
static var authority: String = ""
}
class AuthenticateUser: ObservableObject{
#Published var isLoggedin: Bool = false
func Authenticate(Username:String,Password:String){
let url:String = "http://…./Login.php"
let headers: HTTPHeaders = ["Content-Type":"application/x-www-form-urlencoded"]
let data: Parameters = ["username":Username,"password":Password]
AF.request(url, method: .post, parameters: data, encoding: URLEncoding.default, headers: headers).validate(statusCode: 200 ..< 299).response { AFdata in
do {
guard let jsonObject = try JSONSerialization.jsonObject(with: AFdata.data!, options: .mutableContainers) as? NSDictionary else {
print("Error: Cannot convert data to JSON object")
return
}
guard let prettyJsonData = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) else {
print("Error: Cannot convert JSON object to Pretty JSON data")
return
}
guard let prettyPrintedJson = String(data: prettyJsonData, encoding: .utf8) else {
print("Error: Cannot print JSON in String")
return
}
//if there is no error
if(!(jsonObject.value(forKey: "error") as! Bool)){
print(prettyPrintedJson)
//getting the user from response
let user = jsonObject.value(forKey: "user") as! NSDictionary
//getting user values
let userID = user.value(forKey: "id") as! Int
let name = user.value(forKey: "name") as! String
let authority = user.value(forKey: "authority") as! String
//saving user values
UserDetails.id = String(userID)
UserDetails.name = name
UserDetails.authority = authority
self.isLoggedin = true
}else{
//error message in case of wrong credentials
print("Wrong Credentials")
}
} catch {
print("Error: Trying to convert JSON data to string")
return
}
}
}
}
Login View:
import SwiftUI
struct Login: View {
#StateObject private var loginManager = AuthenticateUser()
#State var username = ""
#State var password = ""
var body: some View {
ZStack{
Rectangle()
.fill(Color(red: 33 / 255, green: 34 / 255, blue: 36 / 255))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
VStack(){
Spacer()
Image("Logo")
Spacer()
VStack(){
Text("RIVIERA BEACH CHALETS")
.font(.title2)
.fontWeight(.semibold)
.foregroundColor(.white)
.multilineTextAlignment(.center)
Text("Administration System")
.font(.headline)
.fontWeight(.light)
.foregroundColor(.white)
}
Spacer()
Text("Sign in")
.font(.largeTitle)
.fontWeight(.medium)
.foregroundColor(.white)
Spacer()
VStack(){
ZStack {
if username.isEmpty {
Text("Username")
.foregroundColor(.white.opacity(0.3))
}
TextField("", text: $username)
.padding()
.multilineTextAlignment(.center)
.foregroundColor(.white)
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.white,lineWidth: 1))
}.padding(.horizontal,5).padding(.vertical,5)
Spacer().frame(height: 15)
ZStack {
if password.isEmpty {
Text("Password")
.foregroundColor(.white.opacity(0.3))
}
SecureField("", text: $password)
.padding()
.multilineTextAlignment(.center)
.foregroundColor(.white)
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.white,lineWidth: 1))
}.padding(.horizontal,5).padding(.vertical,5)
Spacer().frame(height: 15)
HStack {
Button(action:{
//BUTTON ACTION
loginManager.Authenticate(Username: username, Password: password)
},label: {
Spacer()
Text("AUTHENTICATE")
.font(.subheadline)
.fontWeight(.bold)
.foregroundColor(.white.opacity(0.8))
Spacer()
}) .padding()
.background(Color(red: 40 / 255, green: 41 / 255, blue: 43 / 255))
.cornerRadius(20)
}.padding(.horizontal,20).padding(.vertical,5).padding()
Spacer()
}.padding(20)
Spacer()
}
}
}
}
struct LoginPreview: PreviewProvider {
static var previews: some View {
Login()
}
}
let me explain what is going on... and what is my question:
As you can see in code, we have a Json Object response being parsed as NS dictionary while revalidating the UserDetails variables with the data from the Json response, and a published Bool to detect whether logged in or not !
so the question is, how to setup that bool to let the view detect whether user logged in or not ... ? in another words ,what to type in the view code to let the app switch the view to Home view for example if logged in was true ... ? while parsing the user details to show it in that Home view.
Any help would be appreciated !
I'm new to SwiftUI and have worked through the server requests and JSON. I now need to programmatically transition to a new view which is where I get stuck with a "Cannot find 'json' in scope" error on the NavigationLink in ContentView.swift. I've watched videos and read articles but nothing quite matches, and everything I try just seems to make things worse.
JSON response from server
{"status":{"errno":0,"errstr":""},
"data":[
{"home_id":1,"name":"Dave's House","timezone":"Australia\/Brisbane"},
{"home_id":2,"name":"Mick's House","timezone":"Australia\/Perth"},
{"home_id":3,"name":"Jim's House","timezone":"Australia\/Melbourne"}
]}
JSON Struct file
import Foundation
struct JSONStructure: Codable {
struct Status: Codable {
let errno: Int
let errstr: String
}
struct Home: Codable, Identifiable {
var id = UUID()
let home_id: Int
let name: String
let timezone: String
}
let status: Status
let data: [Home]
}
ContentView file
import SwiftUI
struct ContentView: View {
#State private var PushViewAfterAction = false
var body: some View {
NavigationLink(destination: ListView(json: json.data), isActive: $PushViewAfterAction) {
EmptyView()
}.hidden()
Button(action: {
Task {
await performAnAction()
}
}, label: {
Text("TEST")
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue.cornerRadius(10))
.foregroundColor(.white)
.font(.headline)
})
}
func performAnAction() {
PushViewAfterAction = true
return
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
ListView file
import SwiftUI
struct ListView: View {
#State var json: JSONStructure
var body: some View {
VStack {
List (self.json.data) { (home) in
HStack {
Text(home.name).bold()
Text(home.timezone)
}
}
}.onAppear(perform: {
guard let url: URL = URL(string: "https://... ***removed*** ") else {
print("invalid URL")
return
}
var urlRequest: URLRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
URLSession.shared.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
// check if response is okay
guard let data = data, error == nil else { // check for fundamental networking error
print((error?.localizedDescription)!)
return
}
let httpResponse = (response as? HTTPURLResponse)!
if httpResponse.statusCode != 200 { // check for http errors
print("httpResponse Error: \(httpResponse.statusCode)")
return
}
// convert JSON response
do {
self.json = try JSONDecoder().decode(JSONStructure.self, from: data)
} catch {
print(error.localizedDescription)
print(String(data: data, encoding: String.Encoding.utf8)!)
}
print(json)
if (json.status.errno != 0) {
print(json.status.errstr)
}
print("1. \(json.data[0].name)), \(json.data[0].timezone)")
print("2. \(json.data[1].name)), \(json.data[1].timezone)")
}).resume()
})
}
}
struct ListView_Previews: PreviewProvider {
static var previews: some View {
ListView()
}
}
I've tried to keep the code to a minimum for clarity.
It's because there is no "json" in ContentView, you need to pass json object to ListView, but since you load json in ListView, then you need to initialize json in ListView like:
struct ListView: View {
#State var json: JSONStructure = JSONStructure(status: JSONStructure.Status(errno: 0, errstr: ""), data: [JSONStructure.Home(home_id: 0, name: "", timezone: "")])
var body: some View {
and remove it form NavigationLink in ContentView like:
NavigationLink(destination: ListView(), isActive: $PushViewAfterAction) {
or you could build your JSONStructure to accept optional like:
import Foundation
struct JSONStructure: Codable {
struct Status: Codable {
let errno: Int?
let errstr: String?
init() {
errno = nil
errstr = nil
}
}
struct Home: Codable, Identifiable {
var id = UUID()
let home_id: Int?
let name: String?
let timezone: String?
init() {
home_id = nil
name = nil
timezone = nil
}
}
let status: Status?
let data: [Home]
init() {
status = nil
data = []
}
}
but then you need to check for optionals or provide default value like:
struct ListView: View {
#State var json: JSONStructure = JSONStructure()
var body: some View {
VStack {
List (self.json.data) { (home) in
HStack {
Text(home.name ?? "Could not get name").bold()
Text(home.timezone ?? "Could not get timeZone")
}
}
}.onAppear(perform: {
guard let url: URL = URL(string: "https://... ***removed*** ") else {
print("invalid URL")
return
}
var urlRequest: URLRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
URLSession.shared.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
// check if response is okay
guard let data = data, error == nil else { // check for fundamental networking error
print((error?.localizedDescription)!)
return
}
let httpResponse = (response as? HTTPURLResponse)!
if httpResponse.statusCode != 200 { // check for http errors
print("httpResponse Error: \(httpResponse.statusCode)")
return
}
// convert JSON response
do {
self.json = try JSONDecoder().decode(JSONStructure.self, from: data)
} catch {
print(error.localizedDescription)
print(String(data: data, encoding: String.Encoding.utf8)!)
}
print(json)
if (json.status?.errno != 0) {
print(json.status?.errstr)
}
print("1. \(json.data[0].name)), \(json.data[0].timezone)")
print("2. \(json.data[1].name)), \(json.data[1].timezone)")
}).resume()
})
}
}
I'm trying to make a detailed view of a contact from a contacts list. This is the WIP of that view. I am getting the error;
Missing arguments for parameters 'data', 'detailedData' in call
on the line with ContactDetail() in the ContactDetail_Previews struct.
I think I understand that this is because something is missing from the variables data and detailedData, but my confusion comes from how I use similar code for the actual list view of all the contacts, with no such error. I have pasted the code for the whole list view below the code for the detailed view.
Any help would be appreciated!
Contact Detail Code:
import SwiftUI
struct ContactDetail: View {
var data: Response_Detailed.Contact_Detailed
#ObservedObject var detailedData: getData_Detailed
var body: some View {
VStack {
Text(data.first_name + " " + data.last_name)
Text(data.phone_number)
Text(data.birthday)
Text(data.address)
Text(data.updated_date)
Text(data.create_date)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.detailedData.updateDetailed_Data()
}
}
}
}
}
class getData_Detailed: ObservableObject {
#Published var data = [Response_Detailed.Contact_Detailed]()
#Published var id = 1
init() {
updateDetailed_Data()
}
func updateDetailed_Data() {
let url = "DATABASE_LINK\(id)"
let session = URLSession(configuration: .default)
session.dataTask(with: URL(string: url)!) { (data, _, err) in
if err != nil {
print((err?.localizedDescription)!)
return
}
do {
let json = try JSONDecoder().decode(Response_Detailed.self, from: data!)
let oldData = self.data
DispatchQueue.main.async {
self.data = oldData + json.data
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try! encoder.encode(json)
print(String(data: data, encoding: .utf8)!)
}
}
catch {
print(error.localizedDescription)
}
}.resume()
}
}
struct ContactDetail_Previews: PreviewProvider {
static var previews: some View {
ContactDetail()
}
}
struct Response_Detailed: Codable {
struct Contact_Detailed: Codable, Identifiable {
public let id: Int
public let first_name: String
public let last_name: String
public let birthday: String
public let phone_number: String
public let create_date: String
public let updated_date: String
public let address: String
}
public let data: [Contact_Detailed]
enum CodingKeys : String, CodingKey {
case data = "data"
}
}
Contacts List View Code: (Note the same error comes up on the line with NavigationLink.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
HStack {
ContactsList()
.navigationBarTitle("Contacts")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Image(systemName: "plus")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20.0)
}
}
}
}
}
}
struct ContactsList: View {
#ObservedObject var listData = getData()
var body: some View {
List(0..<listData.data.count, id: \.self) {i in
NavigationLink(destination: ContactDetail()) {
if i == self.listData.data.count - 1 {
cellView(data: self.listData.data[i], isLast: true, listData: self.listData)
}
else {
cellView(data: self.listData.data[i], isLast: false, listData: self.listData)
}
}
}
}
}
struct cellView: View {
var data: Response.Contact
var isLast: Bool
#ObservedObject var listData: getData
var body: some View {
VStack(alignment: .leading, spacing: 12) {
if self.isLast {
Text(data.first_name + " " + data.last_name)
.fontWeight(/*#START_MENU_TOKEN#*/.bold/*#END_MENU_TOKEN#*/)
.font(.title2)
.padding(/*#START_MENU_TOKEN#*/[.leading, .bottom, .trailing], 5.0/*#END_MENU_TOKEN#*/)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.listData.updateData()
}
}
}
else {
Text(data.first_name + " " + data.last_name)
.fontWeight(/*#START_MENU_TOKEN#*/.bold/*#END_MENU_TOKEN#*/)
.font(.title2)
.padding(/*#START_MENU_TOKEN#*/[.leading, .bottom, .trailing], 5.0/*#END_MENU_TOKEN#*/)
}
}
.padding(.top, 10)
}
}
class getData: ObservableObject {
#Published var data = [Response.Contact]()
#Published var limit = 15
#Published var skip = 0
init() {
updateData()
}
func updateData() {
let url = "DATABASE_LINK?skip=\(skip)&limit=\(limit)"
let session = URLSession(configuration: .default)
session.dataTask(with: URL(string: url)!) { (data, _, err) in
if err != nil {
print((err?.localizedDescription)!)
return
}
do {
let json = try JSONDecoder().decode(Response.self, from: data!)
let oldData = self.data
DispatchQueue.main.async {
self.data = oldData + json.data
self.limit += 15
self.skip += 15
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try! encoder.encode(json)
print(String(data: data, encoding: .utf8)!)
}
}
catch {
print(error.localizedDescription)
}
}.resume()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Response: Codable {
struct Contact: Codable, Identifiable {
public let id: Int
public let first_name: String
public let last_name: String
public let updated_date: String
}
struct Pagination_Data: Codable {
public let skip: Int
public let limit: Int
public let total: Int
}
public let data: [Contact]
public let pagination: Pagination_Data
enum CodingKeys : String, CodingKey {
case data = "data"
case pagination = "pagination"
}
}
Your ContactsList is giving the only variable an initial value.
#ObservedObject var listData = getData()
Not IAW Apple documentation but the = getData() is the initial value
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
BTW you should change it to
#StateObject var listData = getData()
Your ContactDetail View has two variables without an initial value
struct ContactDetail: View {
var data: Response_Detailed.Contact_Detailed
#ObservedObject var detailedData: getData_Detailed
No = sign so a struct creates an init that looks like this
init(data: Response_Detailed.Contact_Detailed, detailedData: getData_Detailed)
So in your Preview you need to provide the initial values
ContactDetail(data: /.../, detailedData: /.../)
The /.../ symbolizes where you will provide sample data
This API function of mine called fetchAuthorArticles can not fetch JSON data at the first tap. If I close the sheet and tap it once more it does fetch JSON and fills SelectedAuthorView screen accordingly. What might be the reason?
class AuthorService: ObservableObject {
#Published var authorArticles = AuthorList(author: Author(author_id: 0, articles: 0, newspaper_image: "", author_name: "", author_image: "", newspaper: ""), articles: [])
func fetchAuthorArticles(authorID: Int){
isLoadingPage = true
if let selectedAuthorUrl = URL(string:"http://author/article/list/\(authorID)/") {
let session = URLSession(configuration: .default)
var request = URLRequest(url: selectedAuthorUrl)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
print(data)
print(response)
print(error)
if error == nil {
let decoder = JSONDecoder()
if let safeData = data {
do {
let results = try decoder.decode(AuthorArticleList.self, from: safeData)
DispatchQueue.main.async {
self.authorArticles = results
self.isLoadingPage = false
}
} catch {
print(error)
}
}
}
}
task.resume()
}
}
}
AuthorArticleList Model
struct AuthorArticleList:Decodable {
var author: Author
var articles: [Articles]
}
struct Author: Decodable, Identifiable {
var id: Int {
return author_id
}
var author_id: Int
var articles: Int
var newspaper_image: String
var author_name: String
var author_image: String
var newspaper: String
}
struct Articles: Decodable, Identifiable {
var id: Int {
return article_id
}
var article_id: Int
var title: String
var url: String
var abstract: String
var article_date: String
}
SelectedAuthorView
struct SelectedAuthorView: View {
#Binding var selectedAuthor: AuthorPost
#ObservedObject var service = AuthorService()
var cellNumber: Int = 0
let columns: [GridItem] = Array(repeating: GridItem(.flexible(), spacing: 0), count: 2)
var body: some View {
ScrollView(.vertical, showsIndicators: true) {
LazyVGrid(columns: columns, spacing: 0) {
ForEach(Array(service.authorArticles.articles.enumerated()), id: \.1.id) {i, post in
AuthorArticleListItem(articlePost: post, cellNumber: i)
}
.background(Color(.white))
if service.isLoadingPage {
ProgressView()
.padding()
.offset(x: UIScreen.main.bounds.width / 4)
}
}
.onAppear {
self.service.fetchAuthorArticles(authorID: selectedAuthor.author_id)
}
I need to post a https request to login view (SwiftUI), my code follow I have in getres.swift:
so I neet to get value from response and put it in the text
import Foundation
import Combine
struct result: Decodable {
let res, ordercount, rate: String
}
class getres: ObservableObject {
let objectWillChange = PassthroughSubject<getres, Never>()
#Published var authenticated = ""
#Published var todos = [result]() {
didSet {
objectWillChange.send(self)
}
}
func auth(username: String, password: String) {
guard let url = URL(string: "http://company.com/auth.php") else { return }
let body: [String: String] = ["username": username, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data=data else{return}
let fineldata=try! JSONDecoder().decode(result.self, from: data)
DispatchQueue.main.async {
self.todos = [fineldata]
self.authenticated=fineldata.res
}
print(fineldata)
}.resume()
}
}
and in the login page I try to show other view
in this code I will get values from function as json response I will get ordercount and rate I put it in the other view
import SwiftUI
struct ContentView: View {
#State private var username: String = ""
#State private var password: String = ""
#ObservedObject var manager = getres()
var body: some View {
VStack(alignment: .leading) {
if manager.authenticated == "2"{
userdetails()
}else{
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
Button(action: {
self.manager.auth(username: self.username, password: self.password)
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
}.padding()}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and in userdetails this so I need to get values from response
struct userdetails: View {
#State var controller = getres()
var body : some View{
ScrollView(Axis.Set.vertical, showsIndicators: true) {
VStack(spacing: 20){
Image("wlogo").renderingMode(.original); HStack(spacing: 15){
Spacer()
VStack(alignment: .center, spacing: 10) {
Text(???).foregroundColor(Color.white).bold()
.font(.largeTitle)
Text("")
.foregroundColor(Color.white)
.font(.headline) }
Spacer()
}}}}
how can I get ordercount from response and put in
text(???)
in the view userdetails
for example controller.todos.ordercount
I get this error
Value of type '[result]' has no member 'ordercount'
when I try
Text(controller.todos.ordercount)
json response
{"res":"2","ordercount":"20","rate":"5"}
UPDATED ANSWER
1.) it would be helpful if you copy your code in just one part - this is easier for all of us to copy
2.) you should try out your code yourself before you copy or change something in your code manually. it is annoying to find mistakes like:
if manager.authenticated == "2"{
userdetails()
} else{
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
Button(action: {
self.manager.auth(username: self.username, password: self.password)
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
}.padding()}
}
where you are adding .padding() to an if-statement....
3.) you should name class names in that way people can understand what the class if for and start with a capitalized letter like Apple does with all class names
4.) you should also begin View names capitalized (like Apple does)
5.) since i have to access to your page and you did not provide example data and/or password i have no idea what data are coming there...
here is my solution code so far:
i added some faking data, because i cannot access your data ....so you can see something in details.
struct ToDo: Decodable, Identifiable {
var id = UUID().uuidString
let res, ordercount, rate: String
}
class ToDoGetter: ObservableObject {
let objectWillChange = PassthroughSubject<ToDoGetter, Never>()
#Published var authenticated = ""
#Published var todos = [ToDo]() {
didSet {
objectWillChange.send(self)
}
}
let someFakingTodos = [
ToDo(res: "a", ordercount: "5", rate: "75%"),
ToDo(res: "b", ordercount: "52", rate: "5%"),
ToDo(res: "c", ordercount: "566", rate: "7%"),
ToDo(res: "d", ordercount: "53", rate: "33%"),
ToDo(res: "e", ordercount: "15", rate: "44%"),
ToDo(res: "f", ordercount: "345", rate: "10%")
]
func auth(username: String, password: String) {
guard let url = URL(string: "http://company.com/auth.php") else { return }
let body: [String: String] = ["username": username, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data=data else{return}
let fineldata=try! JSONDecoder().decode(ToDo.self, from: data)
DispatchQueue.main.async {
self.todos = [fineldata]
self.authenticated=fineldata.res
}
print(fineldata)
}.resume()
}
}
struct ContentView: View {
#EnvironmentObject var todoGetter : ToDoGetter
#State private var username: String = ""
#State private var password: String = ""
#State var navigateToDetail : Bool = false
var body: some View {
NavigationView {
VStack(alignment: .leading) {
if todoGetter.authenticated == "2"{
Userdetails().environmentObject(todoGetter)
} else{
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
NavigationLink(destination: Userdetails(), isActive: self.$navigateToDetail) {
EmptyView() }
.hidden()
.padding()
Button(action: {
self.todoGetter.auth(username: self.username, password: self.password)
self.navigateToDetail.toggle()
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
}
}
}
}
}
struct Userdetails: View {
#EnvironmentObject var todoGetter : ToDoGetter
var body : some View{
VStack(spacing: 20) {
Image("wlogo").renderingMode(.original); HStack(spacing: 15){
Spacer()
List(todoGetter.someFakingTodos) { todo in
VStack(alignment: .center, spacing: 10) {
HStack {
Text(todo.res).foregroundColor(Color.white).bold()
.font(.largeTitle)
Text(todo.ordercount)
.foregroundColor(Color.white)
.font(.headline)
Text(todo.rate)
.foregroundColor(Color.white)
.font(.headline)
}
}.background(Color.black)
Spacer()
}
}
}
}
}
OLD ANSWER
you call getres 2 times. you have to call it just once and then give the value to the detailview.
the model should only be created once per app.