I have a table in a mySQL database with the variable "show" that I need to convert from an Int to a Bool within SwiftUI.
Not being able to directly declare 'false' as a field value within SQL - I need to code SwiftUI to interpret this integer as a boolean value.
The JSON output reads as
[
{
"establishmentId": 2,
"name": "O'Reilly's Pub",
"slogan": "Insert slogan here."
"city" : "Insert city here."
"state" : "Insert state here."
"email": "oreillys@email.com",
"phone" : "Insert phone here."
"zip" : 12345
"latitude" : 12.22222222
"longitude" : -31.111111
"hours" : "Insert hours here."
"show" : 0
}
]
In SwiftUI I have a structure called 'Establishment'
struct Establishment: Codable, Identifiable {
let id = UUID()
let name: String
let slogan: String
let city: String
let state: String
let email: String
let phone: String
let zip: Int
let signatureItem: String
let latitude: CLLocationDegrees
let longitude: CLLocationDegrees
let logo: URL
let image: URL
var show: Bool
}
I receive errors when trying to iterate between the establishments due to the 'show' variable being an integer:
import SwiftUI
import SDWebImageSwiftUI
import MapKit
struct EstablishmentList: View {
@ObservedObject var store = DataStore()
@State var active = false
@State var activeIndex = -1
@State var activeView = CGSize.zero
var body: some View {
ZStack {
Color.black.opacity(Double(self.activeView.height/500))
.edgesIgnoringSafeArea(.all)
.statusBar(hidden: active ? true : false)
.animation(.linear)
ScrollView {
VStack(spacing: 30) {
Text("Nearby Establishments")
//.font(.largeTitle).bold()
.font(.system(.largeTitle))
.fontWeight(.bold)
.alignmentGuide(.leading, computeValue: { _ in -30})
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.top, 20)
//.blur(radius: active ? 20 : 0)
.animation(nil)
ForEach(store.establishments.indices, id: \.self) { index in
GeometryReader { geometry in
EstablishmentView(show: self.$store.establishments[index].show,
establishment: self.store.establishments[index],
active: self.$active,
index: index,
activeIndex: self.$activeIndex,
activeView: self.$activeView
)
.offset(y: self.store.establishments[index].show ? -geometry.frame(in: .global).minY : 0)
//.opacity(self.activeIndex != index && self.active ? 0 : 1)
.scaleEffect(self.activeIndex != index && self.active ? 0.5 : 1)
.offset(x: self.activeIndex != index && self.active ? screen.width : 0)
}
.frame(height: getCardHeight())
.frame(maxWidth: self.active ? 712 : getCardWidth())
}
}
.frame(width: screen.width)
.padding(.bottom, 300)
.animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))
}
}
}
}
In the EstablishmentView structure I declare '@Binding var show: Bool' and I think this is where my issue rests EstablishmentView
struct EstablishmentView: View {
@Binding var show: Bool
var establishment: Establishment
@Binding var active: Bool
var index: Int
@Binding var activeIndex: Int
@Binding var activeView: CGSize
var body: some View {
ZStack(alignment: .top) {
VStack(alignment: .leading, spacing: 30.0) {
Text(establishment.name)
Text("About this establishment")
.font(.title)
.fontWeight(.bold)
Text(establishment.slogan)
.foregroundColor(Color("secondary"))
Text(establishment.signatureItem)
.foregroundColor(Color("secondary"))
}
.padding(30)
.offset(y: show ? 460 : 0)
.frame(maxWidth: show ? .infinity : getCardWidth())
.frame(maxHeight: show ? screen.height : 280, alignment: .top)
.background(Color("background2"))
.clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
.shadow(color: Color.black.opacity(0.2), radius: 20, x: 0, y: 20)
.opacity(show ? 1 : 0)
VStack {
HStack(alignment: .top) {
VStack(alignment: .leading, spacing: 8.0) {
Text(establishment.name)
.font(.system(size: 24, weight: .bold))
.lineLimit(3)
.foregroundColor(.white)
.animation(nil)
Text(establishment.email.uppercased())
.foregroundColor(Color.white.opacity(0.7))
.animation(nil)
Text(establishment.state)
.foregroundColor(Color.white).opacity(0.7)
.animation(nil)
}
Spacer()
ZStack {
WebImage(url: establishment.image)
.opacity(show ? 0 : 1)
VStack {
Image(systemName: "xmark")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.white)
}
.frame(width: 36, height: 36)
.background(Color.black)
.clipShape(Circle())
.opacity(show ? 1 : 0)
}
}
Spacer()
WebImage(url: establishment.image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(maxWidth: 414)
.frame(height: 140, alignment: .top)
}
.padding(show ? 30 : 20)
.padding(.top, show ? 30 : 0)
.frame(height: show ? 460 : 280)
.frame(maxWidth: show ? .infinity : getCardWidth())
.background(Color(#colorLiteral(red: 0.5843137503, green: 0.8235294223, blue: 0.4196078479, alpha: 1)))
.clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
.shadow(color: Color(#colorLiteral(red: 0.5843137503, green: 0.8235294223, blue: 0.4196078479, alpha: 1)).opacity(0.3), radius: 20, x: 0, y: 20)
.gesture(
show ?
DragGesture()
.onChanged { value in
guard !self.show else { return }
guard value.translation.height > 0 else { return }
guard value.translation.height < 300 else { return }
self.activeView = value.translation
}
.onEnded { value in
if self.activeView.height > 50 {
self.show = false
self.active = false
self.activeIndex = -1
}
self.activeView = .zero
}
: nil
)
.onTapGesture {
self.show.toggle()
self.active.toggle()
if self.show {
self.activeIndex = self.index
} else {
self.activeIndex = -1
}
}
if show {
EstablishmentDetail(establishment: establishment, show: $show, active: $active, activeIndex: $activeIndex)
.background(Color("background1"))
.animation(.linear(duration: 0))
}
}
.gesture(
show ?
DragGesture()
.onChanged { value in
guard value.translation.height > 0 else { return }
guard value.translation.height < 300 else { return }
self.activeView = value.translation
}
.onEnded { value in
if self.activeView.height > 50 {
self.show = false
self.active = false
self.activeIndex = -1
}
self.activeView = .zero
}
: nil
)
.frame(height: show ? screen.height : 280)
.edgesIgnoringSafeArea(.all)
.animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0))
.scaleEffect(1 - self.activeView.height / 1000)
.rotation3DEffect(Angle(degrees: Double(self.activeView.height / -10)), axis: (x: 10, y: -10, z: 0))
.hueRotation(Angle(degrees: Double(self.activeView.height)))
}
}
(I have been working with hardcoded values which is why I never ran into issues when I declared 'var show = false' in my original Establishment struct.)
In an APIManager class I call on my API
import SwiftUI
class APIManager {
func getEstablishments(completion: @escaping ([Establishment]) -> ()) {
guard let url = URL(string: "api address here") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
guard let data = data else { return }
let establishments = try! JSONDecoder().decode([Establishment].self, from: data)
DispatchQueue.main.async {
completion(establishments)
}
}
.resume()
}
and in a DataStore class I initialize a function to utilize the APIManager
import SwiftUI
import Combine
class DataStore: ObservableObject {
@Published var establishments: [Establishment] = []
init() {
getEstablishments()
}
func getEstablishments() {
APIManager().getEstablishments { (establishments) in
self.establishments = establishments
}
}
Can anybody recommend a method of converting the Int to Bool datatype within SwiftUI - that would eliminate my errors. I hope i've provided enough of my code to be clear but let me know if there is more I can provide for clarity's sake.
Edit: Replaced images of code with actual text
Edit: Results from Chris's answer
extension Establishment: Decodable {
private struct JSONSettings: Decodable {
var id = UUID()
var name, slogan, city, state, email, phone, signatureItem: String
var latitude, longitude: Double
var logo, image: String
var zip, show: Int
}
private enum CodingKeys: String, CodingKey {
case establishmentList // Top level
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let settings = try container.decode(JSONSettings.self, forKey: .establishmentList)
id = settings.id
name = settings.name
slogan = settings.slogan
city = settings.city
state = settings.state
email = settings.email
phone = settings.phone
zip = settings.zip
signatureItem = settings.signatureItem
latitude = settings.latitude
longitude = settings.longitude
show = settings.show == 1 ? true : false
}
}