I’ve a view that appears like this:
import SwiftUI
import CoreImage
import CoreImage.CIFilterBuiltins
public struct ShareView: View {
@ObservedObject var viewModel: ShareViewModel
@Surroundings(.presentationMode) var presentationMode: Binding<PresentationMode>
@State var showInfoPopup = false
@State var sessionId: String?
let buttonColor = Coloration(#colorLiteral(crimson: 0.02179291099, inexperienced: 0.05895387381, blue: 0.05662788451, alpha: 1))
let textColor = Coloration(#colorLiteral(crimson: 1, inexperienced: 1, blue: 1, alpha: 1))
let accentColor = Coloration(#colorLiteral(crimson: 0.8581416011, inexperienced: 0.9824749827, blue: 0.7862659097, alpha: 1))
let secondaryTextColor = Coloration(#colorLiteral(crimson: 0.4152581692, inexperienced: 0.4603296518, blue: 0.4508641362, alpha: 1))
@State var isInitalAppear = true
@State var userName: String?
@State var userAlias: String?
@State var identify: String = ""
@State var alias: String = ""
@State var gadgets: [ItemViewModel] = []
@State var totalViewModel: TotalViewModel = TotalViewModel(complete: 0.00, subtotal: 0.00, tax: 0.00)
let clearItems: (() -> Void)
init(gadgets: [ItemViewModel], totalViewModel: TotalViewModel, clearClosure: @escaping (() -> Void) ) {
self.viewModel = ShareViewModel()
self.clearItems = clearClosure
self.gadgets = gadgets
self.totalViewModel = totalViewModel
}
var retryBack : some View { Button(motion: {
self.presentationMode.wrappedValue.dismiss()
clearItems()
}) {
HStack {
Textual content("Begin Over")
.font(.customized("PublicSans-Medium", dimension: 18))
.padding(7)
.padding(.main, 5)
.foregroundColor(textColor)
.padding(.trailing, 5)
}
.background(buttonColor)
.cornerRadius(20.0)
.padding(.backside, 15)
}
}
public var physique: some View {
VStack {
Textual content(viewModel.gadgets.first?.identify ?? "")
Textual content("Don't be concerned. nWe'll do the maths.")
.font(.customized("PublicSans-Daring", dimension: 45))
.foregroundColor(buttonColor)
.padding(.horizontal)
.lineLimit(4)
if let information = viewModel.generateQR(textual content: "https://instance.com/(self.sessionId ?? "")"),
let picture = UIImage(information:information) {
Picture(uiImage: picture)
.interpolation(.none)
.resizable()
.body(width: 200, peak: 200)
HStack {
Button {
UIPasteboard.basic.string = "https://instance.com/(self.sessionId ?? "")"
} label: {
VStack {
Picture(systemName: "doc.on.doc")
.resizable()
.body(width: 20, peak: 20)
.foregroundColor(buttonColor)
.padding(8)
.padding(.main, 3)
.background(accentColor)
.cornerRadius(10.0)
.padding(.trailing, 5)
}
.background(buttonColor)
.cornerRadius(20.0)
.padding(5)
}
NavigationLink(vacation spot: SplitView(viewModel: viewModel, sessionId: $sessionId, alias: $userAlias, identify: $userName), label: {
HStack {
Textual content("Break up")
.font(.customized("PublicSans-Medium", dimension: 22))
.padding(7)
.foregroundColor(textColor)
.padding(.main, 4)
Picture(systemName: "arrow.left.and.proper.sq.")
.resizable()
.body(width: 15, peak: 15)
.foregroundColor(buttonColor)
.padding(8)
.background(accentColor)
.cornerRadius(10.0)
.shadow(coloration: Coloration.black.opacity(0.3), radius: 2, x: 0, y: 3)
.padding(.trailing, 5)
}
.background(buttonColor)
.cornerRadius(20.0)
.padding(3)
})
}
}
}
.padding()
.background(
RoundedRectangle(cornerRadius: 15)
.fill(Coloration.white)
.shadow(coloration: Coloration.black.opacity(0.3), radius: 6, x: 0, y: 3)
)
.navigationBarBackButtonHidden(true)
.onAppear {
if self.isInitalAppear {
self.showInfoPopup = true
self.isInitalAppear = false
Job {
guard self.sessionId == nil else { return }
self.sessionId = await self.viewModel.createShareSession()
}
}
}.sheet(isPresented: $showInfoPopup, onDismiss: {
userAlias = alias
userName = identify
if let userAlias = self.userAlias {
Job {
await self.viewModel.setVenmo(alias: userAlias)
}
}
}) {
UserInfoView(isPresented: $showInfoPopup, userName: $identify, userAlias: $alias)
}
VStack (alignment: .middle) {
Divider()
HStack {
retryBack
Button(motion: {
self.showInfoPopup.toggle()
}) {
HStack {
Textual content("Edit")
.font(.customized("PublicSans-Medium", dimension: 18))
.padding(7)
.padding(.main, 5)
.foregroundColor(textColor)
.padding(.trailing, 5)
}
.background(buttonColor)
.cornerRadius(20.0)
.padding(.backside, 15)
}
}
.padding(.high)
}
.padding()
.onAppear {
self.viewModel.setData(gadgets: self.gadgets, totalViewModel: self.viewModel.totalViewModel)
}
}
}
this view has the next noticed object var:
@ObservedObject var viewModel: ShareViewModel
Which is outlined as such:
import Basis
import SwiftUI
import FirebaseCore
import FirebaseFirestore
@MainActor
class ShareViewModel: ObservableObject {
@Revealed var database = Firestore.firestore()
@Revealed var gadgets: [ItemViewModel] = []
@Revealed var sessionId: String?
@Revealed var isFirstAppear = true
@Revealed var totalViewModel: TotalViewModel
@Revealed var complete: Float
@Revealed var splitTip: Float?
@Revealed var splitTax: Float
@Revealed var individuals: Int = 1
var chosenItems = [UUID: Float]()
public init(gadgets: [ItemViewModel], totalViewModel: TotalViewModel) {
self.gadgets = gadgets
self.totalViewModel = totalViewModel
self.complete = 0
self.splitTip = totalViewModel.tip
self.splitTax = totalViewModel.tax
}
public func generateQR(textual content: String) -> Information? {
let filter = CIFilter.qrCodeGenerator()
guard let information = textual content.information(utilizing: .ascii, allowLossyConversion: false) else { return nil }
filter.message = information
guard let ciimage = filter.outputImage else { return nil }
let rework = CGAffineTransform(scaleX: 10, y: 10)
let scaledCIImage = ciimage.remodeled(by: rework)
let uiimage = UIImage(ciImage: scaledCIImage)
return uiimage.pngData()!
}
public func setVenmo(alias: String) async {
guard let sessionId = sessionId else { return }
let sessionRef = database.assortment("classes").doc(sessionId)
do {
let sessionDoc = strive await sessionRef.getDocument()
guard var sessionData = sessionDoc.information(),
var _ = sessionData["items"] as? [[String: Any]] else {
print("Session or gadgets not discovered")
return
}
sessionData["alias"] = alias
strive await sessionRef.setData(sessionData)
print("Alias up to date efficiently")
} catch {
print("Error updating alias")
}
}
lazy var totalClosure: (ItemViewModel, Bool) -> Void = { [weak self] merchandise, wasAdded in
guard let self = self else { return }
let worth = merchandise.worth
let amount = merchandise.amount
let identify = merchandise.identify
let currentSessionUsers = merchandise.individuals
if wasAdded {
let toAdd = worth
self.chosenItems[item.id] = toAdd
} else {
self.chosenItems.removeValue(forKey: merchandise.id)
}
self.recomputeTotal(individuals: currentSessionUsers)
}
personal func recomputeTotal(individuals: Int) {
var newtotal: Float = 0
for (key, worth) in self.chosenItems {
let splitQuantity = self.gadgets.filter {
$0.id == key
}.first?.patrons.rely ?? 1
newtotal += (worth / Float(splitQuantity))
print("Key: (key), Worth: (worth)")
}
self.splitTax = self.totalViewModel.tax / Float(individuals)
if let tip = self.totalViewModel.tip {
self.splitTip = tip / Float(individuals)
}
self.complete = newtotal + self.splitTax + (self.splitTip ?? 0)
self.individuals = individuals
self.objectWillChange.ship()
}
@MainActor
public func hear(sessionID: String) async {
self.sessionId = sessionID
let _ = Firestore.firestore().assortment("classes").doc(sessionID)
.addSnapshotListener { documentSnapshot, error in
Job {
guard let doc = documentSnapshot else {
print("Error fetching doc: (error!)")
return
}
guard let information = doc.information() else {
print("Doc information was empty.")
return
}
do {
// Convert Firestore doc information to JSON information
let jsonData = strive JSONSerialization.information(withJSONObject: information)
// Decode JSON information utilizing JSONDecoder
let decoder = JSONDecoder()
let sessionData = strive decoder.decode(SessionData.self, from: jsonData)
self.gadgets = sessionData.gadgets
let currentSessionUsers = self.gadgets.first?.individuals
if let currentSessionUsers = currentSessionUsers {
self.recomputeTotal(individuals: currentSessionUsers)
}
} catch {
print("Error decoding information: (error)")
}
print("Present information: (information)")
}
}
}
@MainActor
public func createShareSession() async -> String? {
do {
var itemsData: [[String: Any]] = []
for merchandise in self.gadgets {
let itemData: [String: Any] = [
"id": item.id.uuidString,
"price": item.price,
"name": item.name,
"quantity": item.quantity,
"buyers": [],
"individuals": merchandise.individuals
]
itemsData.append(itemData)
}
let sessionData: [String: Any] = [
"items": itemsData
]
let ref = strive await self.database.assortment("classes").addDocument(information: sessionData)
await hear(sessionID: ref.documentID)
return ref.documentID
} catch {
print("Error including doc: (error)")
return nil
}
}
}
It doesn’t matter what I strive, adjustments to the @Revealed properties within the viewModel don’t replicate within the view. For instance, I’ve Textual content(viewModel.gadgets.first?.identify ?? “”) which I’d anticipate to vary on the viewModel’s listener fireplace. I’ve confirmed that every one my FireStore logic works. How can I repair this and what am I doing unsuitable right here? Thanks!