Home > Blockchain >  How do I let text retrieved from Firestore load upon the view being shown?
How do I let text retrieved from Firestore load upon the view being shown?

Time:02-18

Intro

Hi there. I recently asked a different question asking how to implement user-triggered FCMs. I quickly realised that in order to implement FCMs I needed to add another feature to my app, which is why I am here now. I'm trying, trust me.

My question / problem

In the picture I attached, you can see the text that is supposed to show when the user clicks on the friends tab. But it doesn't do that. It does when I refresh the list, because I put the function in the refreshable attribute. I did also put the function in the view initialisation, but it doesn't do what I want it to do. So my question would be, a) why it doesn't load? and b) what would be an approach to solve my problem?

Code reference

This function is called in the init{} of the view and .refreshable{} of the list inside the view. (I also tried adding it via .onAppear{} in the NavigationLink of the parent view.)

@State var bestfriend: String = ""

func getBestie() {
  let db = Firestore.firestore()
  let docRef = db.collection("users").document(email)

  docRef.getDocument { (document, error) in
    if let document = document, document.exists {
      let bestie = document.get("bestie") as? String ?? "error: bestie"
      bestfriend = String(bestie)
    } else {
      print("Document does not exist")
    }
  }
}

Image for reference

Screenshot

Thanks and annotation

Thank you very much in advance, I'm amazed every day by how amazing this community is and how so many people are willing to help. If you need me to add anything else, of course I will do that. I hope I'll be wise enough one day to help other people with their problems as well.

Edit

The view

import Firebase
import FirebaseAuth
import SDWebImage
import SDWebImageSwiftUI
import SwiftUI

struct View_Friend_Tab: View {
  @ObservedObject var friends_model = Model_User()
  @State var friendWho = ""

  init() {
    friends_model.getFriendlist()
    //friends_model.getBestie()
    getBestie()
  }

  //VARS
  let gifurl = URL(string: "https://c.tenor.com/BTCEb08QgBgAAAAC/osita-iheme-aki-and-pawpaw.gif")
  let avatarURL = URL(
    string:
      "https://firebasestorage.googleapis.com/v0/b/universerp-72af2.appspot.com/o/avatars/anime-girl-white-hair-1-cropped.jpg?alt=media&token=efba4215-850d-41c8-8c90-385f7a572e94"
  )
  @State var showingAlert = false
  @State var showFriendRequests = false
  @State var bestfriend: String = ""

  func getBestie() {
    let db = Firestore.firestore()
    let docRef = db.collection("users").document(email)

    docRef.getDocument { (document, error) in
      if let document = document, document.exists {
        let bestie = document.get("bestie") as? String ?? "error: bestie"
        bestfriend = String(bestie)
      } else {
        print("Document does not exist")
      }
    }
  }

  var body: some View {
    if !showFriendRequests {
      VStack {
        NavigationView {
          /*
                    List (friends_model.friend_list) { item in
                        HStack {
                            Text(item.email)

                            Spacer()
                        }
                    }

                    .refreshable{
                        friends_model.getFriendlist()
                    }
                    .listStyle(.grouped)
                     */

          List {
            Section(header: Text("management")) {
              NavigationLink(destination: View_Friend_Best_Tab()) {
                Label("Select your bestie", systemImage: "star.fill")
              }
              NavigationLink(destination: View_Friend_Requests_Tab()) {
                Label("Manage friend requests", systemImage: "person.fill.questionmark")
              }
              NavigationLink(destination: View_Friend_Add_Tab()) {
                Label("Add friend", systemImage: "person.fill.badge.plus")
              }
            }

            ForEach(friends_model.friend_list) { item in
              let avURL = URL(string: item.avatarURL)
              Section(header: Text(item.username)) {
                HStack {
                  VStack(alignment: .leading) {
                    if bestfriend == item.email {
                      Text("Is your Shin'yū")
                        .foregroundColor(Color("lightRed"))
                        .fontWeight(.bold)
                        .font(.footnote)
                    }
                    Text(item.username)
                      .fontWeight(.bold)
                      .frame(alignment: .leading)
                    Text(item.email)
                      .font(.footnote)
                      .multilineTextAlignment(.leading)
                  }
                  Spacer()
                  WebImage(url: avURL)
                    .resizable(resizingMode: .stretch)
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 50, height: 50)
                    .clipShape(Circle())
                    .shadow(radius: 5)
                    .overlay(Circle().stroke(Color.black, lineWidth: 1))
                }
                Button("Remove", role: .destructive) {
                  showingAlert = true
                }
                .alert("Do you really want to remove this friend?", isPresented: $showingAlert) {
                  HStack {
                    Button("Cancel", role: .cancel) {}
                    Button("Remove", role: .destructive) {
                      friendWho = item.email
                      removeFriend()
                      withAnimation {
                        friends_model.getFriendlist()
                      }
                    }
                  }
                }
              }
            }
          }
          .navigationTitle("Your Friends")
          .navigationViewStyle(.automatic)
          .refreshable {
            friends_model.getFriendlist()
            getBestie()
          }
          .listStyle(.insetGrouped)
          Spacer()
        }
      }
    } else {
      View_Friend_Requests_Tab()
    }
  }

}

struct View_Friend_Tab_Previews: PreviewProvider {
  static var previews: some View {
    View_Friend_Tab()
  }
}

As previously stated, the function is being called in the init block and when the list is refreshed.

CodePudding user response:

As a general recommendation, use view models to keep your view code clean.

In SwiftUI, a view's initialiser should not perform any expensive / long-running computations. Keep in mind that in SwiftUI, a view is only a description of your UI, not the UI itself. Any state management should be handled outside of the initialiser.

In your case, use .onAppear or .task:

import Firebase
import FirebaseAuth
import SDWebImage
import SDWebImageSwiftUI
import SwiftUI

class FriendsViewModel: ObservableObject {
  @Published var bestfriend: String = ""

  func getBestie() {
    let db = Firestore.firestore()
    let docRef = db.collection("users").document(email)

    docRef.getDocument { (document, error) in
      if let document = document, document.exists {
        // consider using Codable for mapping - see https://peterfriese.dev/posts/firestore-codable-the-comprehensive-guide/
        let bestie = document.get("bestie") as? String ?? "error: bestie"
        self.bestfriend = String(bestie)
      } else {
        print("Document does not exist")
      }
    }
  }

  // add other functions and properties here.
}

struct FriendsView: View {
  @ObservedObject var viewModel = FriendsViewModel()

  //VARS
  let gifurl = URL(string: "https://c.tenor.com/BTCEb08QgBgAAAAC/osita-iheme-aki-and-pawpaw.gif")
  let avatarURL = URL(
    string:
      "https://firebasestorage.googleapis.com/v0/b/universerp-72af2.appspot.com/o/avatars/anime-girl-white-hair-1-cropped.jpg?alt=media&token=efba4215-850d-41c8-8c90-385f7a572e94"
  )
  @State var showingAlert = false
  @State var showFriendRequests = false
  @State var bestfriend: String = ""

  var body: some View {
    if !showFriendRequests {
      VStack {
        NavigationView {
          List {
            Section(header: Text("management")) {
              NavigationLink(destination: SelectBestieView()) {
                Label("Select your bestie", systemImage: "star.fill")
              }
              NavigationLink(destination: ManageFriendRequestsView()) {
                Label("Manage friend requests", systemImage: "person.fill.questionmark")
              }
              NavigationLink(destination: AddFriendsView()) {
                Label("Add friend", systemImage: "person.fill.badge.plus")
              }
            }

            ForEach(viewModel.friends) { friend in
              let avURL = URL(string: friend.avatarURL)
              Section(header: Text(friend.username)) {
                HStack {
                  VStack(alignment: .leading) {
                    if bestfriend == friend.email {
                      Text("Is your Shin'yū")
                        .foregroundColor(Color("lightRed"))
                        .fontWeight(.bold)
                        .font(.footnote)
                    }
                    Text(friend.username)
                      .fontWeight(.bold)
                      .frame(alignment: .leading)
                    Text(friend.email)
                      .font(.footnote)
                      .multilineTextAlignment(.leading)
                  }
                  Spacer()
                  WebImage(url: avURL)
                    .resizable(resizingMode: .stretch)
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 50, height: 50)
                    .clipShape(Circle())
                    .shadow(radius: 5)
                    .overlay(Circle().stroke(Color.black, lineWidth: 1))
                }
                Button("Remove", role: .destructive) {
                  showingAlert = true
                }
                .alert("Do you really want to remove this friend?", isPresented: $showingAlert) {
                  HStack {
                    Button("Cancel", role: .cancel) {}
                    Button("Remove", role: .destructive) {
                      friendWho = friend.email
                      viewModel.removeFriend()
                      withAnimation {
                        viewModel.getFriendlist()
                      }
                    }
                  }
                }
              }
            }
          }
          .navigationTitle("Your Friends")
          .navigationViewStyle(.automatic)
          .onAppear {
            viewModel.getFriendlist()
            viewModelgetBestie()
          }
          .refreshable {
            viewModel.getFriendlist()
            viewModelgetBestie()
          }
          .listStyle(.insetGrouped)
          Spacer()
        }
      }
    } else {
      FriendRequestsView()
    }
  }

}

struct FriendsViewPreviews: PreviewProvider {
  static var previews: some View {
    FriendsView()
  }
}
  • Related