When I press the checkbox, using the code below, it updates the data in firebase, but when I try to uncheck, it takes two presses before it shows it as unpressed, even though on the first press, it updates in firebase.
struct ReportsUI: View {
#State var hasbeenbilled = false
var body: some View {
VStack {
VStack {
HStack {
VStack {
ZStack {
VStack {
}
.frame(width: 30, height: 30)
.background(hasbeenbilled == true ? .blue : colorScheme == .dark ? .black : .white)
.cornerRadius(5)
if hasbeenbilled {
Image(systemName: "checkmark")
.foregroundColor(.white)
}
}
}
.frame(width: 35, height: 35)
.background(.blue)
.cornerRadius(5)
.onTapGesture {
withAnimation {
hasbeenbilled.toggle()
}
let document = db.collection("Flights").document("\(flightnum)")
document.updateData([
"hasBeenBilled": hasbeenbilled,
]) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document successfully updated")
}
}
}
}
}
}
.padding(.leading)
}
}
I tried removing the firebase update code, and it worked perfectly, except I need it to update in firebase. What can I do?
Related
I have a button ("Next Word") that when pressed shows a new view ("PracticeResult"). The idea is that everytime you press it, a new random word appears on the screen. But so far, I have to press the button twice to get it to show the next image because it's triggered with a boolean state.
I've tried changing the State back to false with an ".onAppear" toggle but it doesn't work. I've also tried using an origin State to toggle the variable back to false but it hasn't worked either. I'm quite new to SwiftUI so any tips would be appreciated! Thanks in advance.
struct PracticeView: View {
#State var isTapped: Bool = false
var body: some View {
NavigationView {
ZStack {
Color.white
VStack() {
Image("lightlogolong")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300.0, height: 100.0)
.cornerRadius(100)
.animation(.easeIn, value: 10)
NavigationLink(destination:
ContentView().navigationBarBackButtonHidden(true) {
HomeButton()
}
Group {
if (isTapped == true){
PracticeResult()
}
}.onAppear{
isTapped.toggle()
}
Button("Next Word", action:{
self.isTapped.toggle()
})
.padding()
.frame(width: 150.0, height: 40.0)
.font(.title2)
.accentColor(.black)
.background(Color("appblue"))
.clipShape(Capsule())
}
}
}
}
}
You could try this simple approach, using a UUID or something like it,
to trigger your PracticeResult view every time you tap the button. Note in particular the PracticeResult().id(isTapped)
struct PracticeView: View {
#State var isTapped: UUID? // <--- here
var body: some View {
NavigationView {
ZStack {
Color.white
VStack() {
Image("lightlogolong")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300.0, height: 100.0)
.cornerRadius(100)
.animation(.easeIn, value: 10)
NavigationLink(destination:
ContentView().navigationBarBackButtonHidden(true) {
HomeButton()
}
if isTapped != nil {
PracticeResult().id(isTapped) // <--- here
}
Button("Next Word", action:{
isTapped = UUID() // <--- here
})
.padding()
.frame(width: 150.0, height: 40.0)
.font(.title2)
.accentColor(.black)
.background(Color.blue)
.clipShape(Capsule())
}
}
}
}
}
// for testing
struct PracticeResult: View {
#State var randomWord: String = UUID().uuidString
var body: some View {
Text(randomWord)
}
}
if you want your button trigger a new random word appears on the screen, you should use button to change that random word
for example (you can try it on Preview):
struct PracticeView: View {
let words = ["one","two","three"]
#State var wordToDisplay: String?
var body: some View {
VStack {
if let wordToDisplay = wordToDisplay {
Text(wordToDisplay)
}
Spacer()
Button("Next Word") {
wordToDisplay = words.filter { $0 != wordToDisplay }.randomElement()
}
}.frame(height: 50)
}
}
I have the following error in my code. Please help me why I cannot use my HymnLyrics() struct inside button action. It works for NavigationLink of destination but I don't wanna use it.
import SwiftUI
struct ContentView: View {
#EnvironmentObject var tappingSwitches: TapToggle
let zoLyrics: [Lyric] = LyricList.hymnLa.sorted { lhs, rhs in
return lhs.zoTitle < rhs.zoTitle
}
var body: some View {
ScrollView {
ForEach(zoLyrics, id: \.id) { zoLyric in
VStack {
Button(action: {
HymnLyrics(lyrics: LyricList.hymnLa)// Here is the error, I can use directly by using NavagationLink
self.tappingSwitches.isHymnTapped.toggle()
}, label: {
HStack {
Text(zoLyric.zoTitle)
.foregroundColor(Color("bTextColor"))
.lineLimit(1)
.minimumScaleFactor(0.5)
Spacer()
Text("\(zoLyric.number)")
.foregroundColor(Color("bTextColor"))
}
})
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding([.leading, .bottom, .trailing])
}
}
}
}
I'm trying to include some blog posts from my WordPress site into my app. I've tested the API using the individual post Ids for each post and I got it to load the data in my view. However, I'm now trying to fetch an array but it doesn't seem to be fetching the IDs related to the posts to populate the view. What am I doing wrong here?
let content: MarkdownData
#State var beholdarticles: BeholdArticle?
#State private var htmlContent = ""
let articles: [BeholdArticle] = []
private func loadArticle() {
guard let url = URL(string: "https://behold.hagleyparksda.com/wp-json/wp/v2/posts") else {
return
}
URLSession.shared.dataTask(with: url) {data, response, error in
guard let data = data else { return }
if let decodedData = try? JSONDecoder().decode(BeholdArticle.self, from: data){
DispatchQueue.main.async {
self.beholdarticles = decodedData
}
}
}.resume()
}
This is the ForEach loop
var body: some View {
ScrollView (.horizontal) {
ForEach(articles) { item in
ZStack {
if beholdarticles?.thumbnail != nil {
WebImage(url: URL(string: beholdarticles!.thumbnail)!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:350, height: 450)
} else {
Image("behold_imagecard")
.resizable()
.aspectRatio(contentMode: .fill)
}
HStack {
VStack (alignment: .leading) {
Text(beholdarticles?.title.rendered ?? "Loading...")
.font(.system(size: 30, weight: .bold))
.foregroundColor(Color.white)
.frame(width: 270)
// Text(beholdarticles?.title.rendered ?? "Loading...")
// .font(.system(size: 18, weight: .regular))
// .foregroundColor(Color.white)
// .frame(width: 270)
}
Spacer()
}
VStack {
Spacer()
HStack {
Image(uiImage: #imageLiteral(resourceName: "healthicon"))
Text("Spirituality")
.font(.system(size: 23))
.foregroundColor(Color.white)
Spacer()
}
.background(VisualEffectBlurView(blurStyle: .systemUltraThinMaterial))
}.onAppear{
loadArticle()
}
} .frame(width:350, height: 450)
.shadow(color: Color(#colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)) .opacity(0.2), radius: 20, x: /*#START_MENU_TOKEN#*/0.0/*#END_MENU_TOKEN#*/, y:14)
.cornerRadius(30)
}
}
My data model
struct BeholdArticle: Decodable, Identifiable {
var id: Int
var slug: String
var link: String
var thumbnail: String
var title: BeholdArticleTitle
var content: BeholdArticleContent
enum CodingKeys: String, CodingKey {
case thumbnail = "jetpack_featured_media_url"
case slug, link, title, content
case id = "id"
}
}
struct BeholdArticleTitle: Decodable {
var rendered: String
}
struct BeholdArticleContent: Decodable {
var rendered: String
}
I'm simply trying to populate my loop with the data, but it doesnt seem to be grabbing the ID's from api call. Need some help here
I still have the image URL wrapped in a conditional statement. At current the images wont come through. How do I adjust this to the updated setup?
if beholdarticles?.thumbnail != nil {
WebImage(url: URL(string: item.thumbnail)!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:350, height: 450)
} else {
Image("behold_imagecard")
.resizable()
.aspectRatio(contentMode: .fill)
}
Here's the updated image code:
ForEach(articles) { article in
ZStack {
if article.thumbnail != nil {
WebImage(url: URL(string: article.thumbnail)!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:350, height: 450)
} else {
Image("behold_imagecard")
.resizable()
.aspectRatio(contentMode: .fill)
}
If you want to decode the JSON from that URL endpoint, you're going to need to use [BeholdArticle].self instead of BeholdArticle.self, since it's an array of data.
Also, instead of calling loadArticle on each element of the ForEach (which will never get called, since it doesn't have data in it at the beginning), call it at the top level of the view.
Here's a pared down example:
struct ContentView: View {
#State private var articles : [BeholdArticle] = []
var body: some View {
ScrollView {
VStack (alignment: .leading) {
ForEach(articles) { article in
Text(article.title.rendered)
.multilineTextAlignment(.leading)
if let thumbnailURL = URL(string: article.thumbnail) {
WebImage(url: thumbnailURL)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width:350, height: 450)
}
}
}
}
.onAppear {
loadArticles()
}
}
private func loadArticles() {
guard let url = URL(string: "https://behold.hagleyparksda.com/wp-json/wp/v2/posts") else {
return
}
URLSession.shared.dataTask(with: url) {data, response, error in
guard let data = data else { return }
if let decodedData = try? JSONDecoder().decode([BeholdArticle].self, from: data){
DispatchQueue.main.async {
self.articles = decodedData
}
}
}.resume()
}
}
Trying to init CustomButton(title: "Add", icon: .add, status: .enable)
My code is below. I do get the title but enums are not working.
Plus recieving error
Cannot convert value of type 'Image' to expected argument type 'String'
at Image(icon)
import SwiftUI
struct CustomButton: View {
var title: String
var icon: String
var status: Color
var body: some View {
Button(action: {
}) {
Text(title)
.foregroundColor(.white)
.background(Color(.green))
.font(Font.custom("SFCompactDisplay", size: 14))
Image(icon)
.renderingMode(.original)
.foregroundColor(.white)
}
}
enum Icon {
case add
case edit
var image: Image {
switch self {
case .add:
return Image("Add")
case .edit:
return Image("Edit")
}
}
}
enum Status {
case enable
case disable
var color : Color {
switch self {
case .enable:
return Color(.green)
case .disable:
return Color(.gray)
}
}
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon.image
self.status = status.color
}
}
I assume you wanted this
struct CustomButton: View {
var title: String
var icon: Icon
var status: Color
var body: some View {
Button(action: {
}) {
Text(title)
.foregroundColor(.white)
.background(Color(.green))
.font(Font.custom("SFCompactDisplay", size: 14))
icon.image
.renderingMode(.original)
.foregroundColor(.white)
}
}
enum Icon {
case add
case edit
var image: Image {
switch self {
case .add:
return Image("Add")
case .edit:
return Image("Edit")
}
}
}
enum Status {
case enable
case disable
var color : Color {
switch self {
case .enable:
return Color(.green)
case .disable:
return Color(.gray)
}
}
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon
self.status = status.color
}
}
I figured it out. It works now.
struct CustomButton: View {
let title: String
let icon : String
let status: Color
#State private var buttonDisabled = true
var body: some View {
Button(action: {
}) {
ZStack(alignment:.bottom) {
HStack {
Text(title)
.foregroundColor(.white)
.font(Font.custom("SFCompactDisplay-Bold", size: 20))
.bold()
.fontWeight(.bold)
.background(status)
Image(icon)
.renderingMode(.original)
.foregroundColor(.white)
.background(Color(.white))
}
.frame(width: 335, height: 20, alignment: .center)
.padding()
.background(status)
}
.cornerRadius(10)
}
}
enum Icon {
case add
case edit
case none
var image: String {
switch self {
case .add:
return "Add"
case .edit:
return "Edit"
case .none:
return "empty"
}
}
}
enum Status {
case enable
case disable
}
init(title: String, icon: Icon, status: Status) {
self.title = title
self.icon = icon.image
if status == .enable {
self.status = Color(#colorLiteral(red: 0, green: 0.6588235294, blue: 0.5254901961, alpha: 1))
} else {
self.status = Color(#colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1))
}
}
}
struct CustomButton_Previews: PreviewProvider {
static var previews: some View {
CustomButton(title: "Odeme Yontemi Ekle", icon: .none, status: .enable)
}
}
I have a button that increments a firebase value by one, however I'm trying to only allow that button to be tapped once. Tried a few things but couldn't get it work correctly is there an simple way to get this working?
Button(action: {
let db = Firestore.firestore()
let like = Int.init(self.likes)!
db.collection("posts").document(self.id).updateData(["likes": "\(like + 1)"]) { err in
if err != nil {
print(err)
return
}
print("updated...")
}
}) {
Image(systemName: "arrow.up.square")
.frame(width: 26, height: 26)
}
Here is a simple demo:
struct ContentView: View {
#State var buttonTapped = false
var body: some View {
Button(action: {
self.buttonTapped.toggle()
// other actions...
}) {
Text("Tap me")
}
.disabled(buttonTapped)
}
}