devOP1
devOP1

Reputation: 477

ProgressView Not Updating

I am trying to observe the progress when uploading an image to firebase storage. The progress is being updated in the console however my ProgressView does not update. Everything else seems to be working as expected. Any idea what I'm doing wrong?

class UserManager: ObservableObject  {

@Published var taskProgress: Float = 0.0
let user = Auth.auth().currentUser



func uploadProfilePicture(image: UIImage) {
    
    let uploadRef = FirebaseReferenceManager.storage.reference(withPath: "profile/\(user!.uid)")
    
    guard let imageData = image.jpegData(compressionQuality: 0.75) else {
        return
    }
    
    let uploadMetaData = StorageMetadata.init()
    uploadMetaData.contentType = "image/jpeg"
    
    let taskReference = uploadRef.putData(imageData, metadata: uploadMetaData) { (downloadMetaData, error) in
        if let error = error {
            print(error.localizedDescription)
            return
        } else {
            print("Successfully Uploaded Profile Picture to Firebase Storage")
            let downloadRef = FirebaseReferenceManager.storage.reference(withPath: "profile/\(self.user!.uid)")
            downloadRef.downloadURL { (url, error) in
                
                if let error = error {
                    print(error.localizedDescription)
                    return
                }
                
                FirebaseReferenceManager.root.collection(FirebaseKeys.CollectionPath.users).document(self.user!.uid).setData([FirebaseKeys.UsersFieldPath.photoURL : url!.absoluteString], merge: true)
            }
            
            

        }
    }

    
    taskReference.observe(.progress) { [weak self] (snapshot) in
        DispatchQueue.main.async {
            guard let pctThere = snapshot.progress?.fractionCompleted else {return}
            print(pctThere)
            self?.taskProgress = Float(pctThere)
        }

    }
    taskReference.resume()
    

}

}

In my view I put the following

@EnvironmentObject var userManager: UserManager

ProgressView(value: userManager.taskProgress).progressViewStyle(LinearProgressViewStyle())

Here is how the class is initialized:

struct SwiftUIView: View {
@StateObject var userManager = UserManager()

var body: some View {
    
    TabView {
        
        HomeView().tabItem {
            Image("home")
            Text("Home")
            
        }
        

        SearchView().tabItem {
            Image("search")
            Text("Search")
            
        }
        
        DiscoverView().tabItem {
            Image("discover")
            Text("Discover")
            
        }
        
        OrdersView().tabItem {
            Image("calendar")
            Text("Orders")
            
        }
        
        InboxView().tabItem {
            Image("inbox")
            Text("Inbox")
            
        }
    }
    .environmentObject(userManager)
}

}

And then I pass it down deeper into the hierarchy using

    @EnvironmentObject var userManager: UserManager

Here is where uploadProfilePicture() is called:

struct ImagePicker: UIViewControllerRepresentable {

var sourceType: UIImagePickerController.SourceType = .photoLibrary

@Binding var selectedImage: UIImage
@Environment(\.presentationMode) private var presentationMode


func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
    
    let imagePicker = UIImagePickerController()
    imagePicker.delegate = context.coordinator
    imagePicker.allowsEditing = true
    imagePicker.sourceType = sourceType
    
    return imagePicker
}

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}


func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

}


class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
 
    let parent: ImagePicker
    @ObservedObject private var userManager = UserManager()

 
    init(_ parent: ImagePicker) {
        self.parent = parent
    }
 
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
 
        if let image = info[.editedImage] as? UIImage {
            parent.selectedImage = image
            userManager.uploadProfilePicture(image: image)
        }
        

        parent.presentationMode.wrappedValue.dismiss()
    }
}

}

Upvotes: 1

Views: 621

Answers (1)

jnpdx
jnpdx

Reputation: 52397

From the comments, we deduced that it was a different UserManager instance. Here would be an example of how to pass the same instance into the Coordinator (this is assuming that ImagePicker exists in an environment where @EnvironmentObject var userManager: UserManager is available).

struct ImagePicker: UIViewControllerRepresentable {
    
    var sourceType: UIImagePickerController.SourceType = .photoLibrary
    
    @Binding var selectedImage: UIImage
    @Environment(\.presentationMode) private var presentationMode
    @EnvironmentObject private var userManager: UserManager //<-- Here
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = context.coordinator
        imagePicker.allowsEditing = true
        imagePicker.sourceType = sourceType
        
        return imagePicker
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self, userManager: userManager)  //<-- Here
    }
    
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
        
    }
    
    
    class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        
        let parent: ImagePicker
        let userManager: UserManager
        
        init(_ parent: ImagePicker, userManager: UserManager) {  //<-- Here
            self.parent = parent
            self.userManager = userManager  //<-- Here
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            
            if let image = info[.editedImage] as? UIImage {
                parent.selectedImage = image
                userManager.uploadProfilePicture(image: image)
            }
            
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

Upvotes: 1

Related Questions