iOS Development

ios – Loading listing on Firebase database and Firestore

Spread the love


I’m dealing with a difficulty in my app that I’m not in a position to remedy.
My undertaking has completely different views the place the consumer can choose some meals for the purchasing listing.
When the consumer has chosen by classes all the weather so as to add within the listing, they’re saved and proven up in firstView the place are situated all listing saved by customers.
My challenge is that I’m attempting to see solely these components within the listing the place had been loaded, and now I’m dealing with the difficulty like a loop, as a result of once I faucet on the cells, these components are blended and displaying up in numerous listing the place weren’t loaded. I attempted so as to add a var with distinctive id for aspect or listing to keep away from it, however was unattainable, I used to be mistaken with one thing else. Can I’ve some assist please?

import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
import LocalAuthentication

class FirstView: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    
    func didSaveNewList(listName: String, gadgets: [ListTextField]) {
        guard !listName.isEmpty else {
            print("El nombre de la lista no puede estar vacío.")
            print("Guardando nueva lista con nombre: (listName) y elementos: (gadgets)")

            return
        }
        
        let listData: [String: Any] = [
            "listName": listName,
            "items": items.map { $0.toAnyObject() }
        ]
        
        let userRef = Database.database().reference(withPath: "userLists/(Auth.auth().currentUser!.uid)/(listName)")
        userRef.setValue(listData) { error, _ in
            if let error = error {
                print("Information couldn't be saved: (error).")
            } else {
                print("Information saved efficiently!")
                self.lists[listName] = gadgets
                self.firstTableView.reloadData()
            }
        }
    }
    
    var lists: [String: [ListTextField]] = [:]
    var listName: String?
    var gadgets: [ListTextField]?
    
    @IBOutlet weak var firstTableView: UITableView!
    
    let gradientLayer = CAGradientLayer()
    let floatingButtonGradientLayer = CAGradientLayer()
    let floatingButton = UIButton(sort: .system)
    let createListLabel = UILabel()
    let loginButton = UIButton(sort: .system)
    let premiumButton = UIButton(sort: .system)
    
    override func viewWillAppear(_ animated: Bool) {
        tremendous.viewWillAppear(animated)
        if let consumer = Auth.auth().currentUser {
            loadListsFromFirebase(uid: consumer.uid)
        }
    }
    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        setupUI()
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    func newListSaved(listName: String, gadgets: [Product]) {
        
        let convertedItems = gadgets.map { product in
            ListTextField(id: product.id, 
                          title: product.name_es,
                          subtitle: product.class,
                          isChecked: product.isChecked)
        }
        print("Nueva lista guardada con nombre: (listName) y productos: (gadgets)")
        print("Elementos convertidos: (convertedItems)")
        lists[listName] = convertedItems
        firstTableView.reloadData()
    }
    
    
    func navigateToScreen(isAuthenticated: Bool) {
        if isAuthenticated && isUserRegistered() {
            self.tabBarController?.selectedIndex = 0
        } else {
            self.proceedToLoginOrSignUp()
        }
    }
    
    func proceedToLoginOrSignUp() {
        print("proceedToLoginOrSignUp referred to as")
        if isUserRegistered() {
            self.tabBarController?.selectedIndex = 0
        } else {
            if let signUpVC = UIStoryboard(title: "Major", bundle: nil).instantiateViewController(withIdentifier: "LoginScreen") as? LoginScreen {
                self.navigationController?.pushViewController(signUpVC, animated: true)
            } else {
                print("Error: No se pudo instanciar SignUpScreen")
            }
        }
    }
    
    func showLogoutAlert() {
        print("showLogoutAlert referred to as")
        let alertController = UIAlertController(
            title: NSLocalizedString("Logout", remark: "Cerrar sesión"),
            message: NSLocalizedString("Are you positive you wish to logout?", remark: "¿Estás seguro de que quieres cerrar sesión?"),
            preferredStyle: .alert
        )
        
        let logoutAction = UIAlertAction(title: NSLocalizedString("Sure", remark: "Sí"), model: .harmful) { [weak self] _ in
            do {
                strive Auth.auth().signOut()
                self?.proceedToLoginOrSignUp()
            } catch {
                print("Error al cerrar sesión: (error)")
            }
        }
        alertController.addAction(logoutAction)
        
        let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", remark: "Cancelar"), model: .cancel, handler: nil)
        alertController.addAction(cancelAction)
        
        self.current(alertController, animated: true, completion: nil)
    }
    
    func isUserRegistered() -> Bool {
        print("isUserRegistered referred to as")
        return Auth.auth().currentUser != nil
    }
    
    
    
    @objc func goToPremiumSection() {
        // TODO
    }
    
    @objc func showCreateListAlert() {
        let alertController = UIAlertController(
            title: NSLocalizedString("New Listing", remark: ""),
            message: NSLocalizedString("Enter listing title", remark: ""),
            preferredStyle: .alert
        )
        alertController.addTextField { textField in
            textField.placeholder = NSLocalizedString("Listing title", remark: "")
        }
        let confirmAction = UIAlertAction(
            title: NSLocalizedString("Settle for", remark: ""),
            model: .default
        ) { [weak self] _ in
            guard let self = self else { return }
            if let listName = alertController.textFields?.first?.textual content, !listName.isEmpty {
                if self.lists.keys.comprises(listName) {
                    return
                }
                if let consumer = Auth.auth().currentUser {
                    let ref = Database.database().reference().baby("lists").baby(consumer.uid).childByAutoId()
                    ref.setValue(listName)
                } else {
                    self.lists[listName] = []
                }
                
                let newListVC = UIStoryboard(title: "Major", bundle: nil).instantiateViewController(withIdentifier: "NewListView") as! NewListView
                newListVC.listName = listName.capitalized
                self.navigationController?.pushViewController(newListVC, animated: true)
            } else {
                print(NSLocalizedString("load_error", remark: ""))
            }
        }
        
        alertController.addAction(confirmAction)
        alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel", remark: ""), model: .cancel, handler: nil))
        current(alertController, animated: true, completion: nil)
    }
    
    non-public func loadListsFromFirebase(uid: String) {
        print("Inicio de loadListsFromFirebase para el usuario (uid)")
        let ref = Database.database().reference().baby("userLists").baby(uid)
        ref.observe(.worth) { [weak self] snapshot in
            print("Observando cambios en Firebase")
            var newLists: [String: [ListTextField]] = [:]
            for baby in snapshot.youngsters {
                if let childSnapshot = baby as? DataSnapshot, let worth = childSnapshot.worth as? [String: Any] {
                    let listName = childSnapshot.key
                    print("Procesando lista con nombre: (listName)")
                    if let itemsData = worth["items"] as? [[String: Any]] {
                        var gadgets: [ListTextField] = []
                        for itemData in itemsData {
                            if let id = itemData["id"] as? String,
                               let title = (itemData["name_es"] as? String) ?? (itemData["title"] as? String),
                               let subtitle = (itemData["category"] as? String) ?? (itemData["subtitle"] as? String),
                               let isChecked = itemData["isChecked"] as? Bool {
                                let listItem = ListTextField(id: id, title: title, subtitle: subtitle, isChecked: isChecked)
                                gadgets.append(listItem)
                                print("Merchandise agregado a la lista (listName): (listItem)")
                            }
                        }
                        newLists[listName] = gadgets
                    } else if let itemsData = worth["items"] as? [String: [String: Any]], let nestedItems = itemsData["items"] {
                        var gadgets: [ListTextField] = []
                        for (id, itemData) in nestedItems {
                            if let itemData = itemData as? [String: Any],
                               let title = itemData["title"] as? String,
                               let subtitle = itemData["subtitle"] as? String,
                               let isChecked = itemData["isChecked"] as? Bool {
                                let listItem = ListTextField(id: id, title: title, subtitle: subtitle, isChecked: isChecked)
                                gadgets.append(listItem)
                                print("Merchandise anidado agregado a la lista (listName): (listItem)")
                            }
                        }
                        newLists[listName] = gadgets
                    }
                }
            }
            self?.lists = newLists
            DispatchQueue.primary.async {
                print("Recargando datos de la tabla")
                self?.firstTableView.reloadData()
            }
        }
    }



       //    Extensión de la clase:
       
       func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
           print("Actualizando número de filas en la sección: (part), rely: (lists.rely)")

           return lists.keys.rely
       }
       
       func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
           print("Creando celda para indexPath: (indexPath), listas: (lists)")
           guard let cell = tableView.dequeueReusableCell(withIdentifier: FirstCell.firstIdentifier, for: indexPath) as? FirstCell else {
               fatalError("The dequeued cell just isn't an occasion of FirstCell.")
           }
           
           let listName = Array(lists.keys).sorted()[indexPath.row]
           cell.mainLabel.textual content = listName.capitalized
           cell.layer.cornerRadius = 10
           cell.clipsToBounds = true
           
           print("Celda creada con el nombre de la lista: (listName)")
           return cell
       }
  
    
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(model: .harmful, title: NSLocalizedString("Eliminar", remark: "")) { (motion, view, completion) in
            let alert = UIAlertController(title: NSLocalizedString("Eliminar", remark: ""), message: NSLocalizedString("¿Estás seguro de que quieres eliminar este elemento?", remark: ""), preferredStyle: .alert)
            
            alert.addAction(UIAlertAction(title: NSLocalizedString("Sí", remark: ""), model: .harmful, handler: { _ in
                // Borrar el elemento de la lista native
                let listKey = Array(self.lists.keys)[indexPath.row]
                self.lists.removeValue(forKey: listKey)
                
                // Actualizar la tabla
                tableView.deleteRows(at: [indexPath], with: .automated)
                completion(true)
            }))
            
            alert.addAction(UIAlertAction(title: NSLocalizedString("No", remark: ""), model: .cancel, handler: { _ in
                completion(false)
            }))
            
            self.current(alert, animated: true)
        }
        return UISwipeActionsConfiguration(actions: [deleteAction])
    }

       func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
           tableView.deselectRow(at: indexPath, animated: true)
           
           let selectedListName = Array(lists.keys)[indexPath.row]
           let selectedListItems = lists[selectedListName]
           
           let storyboard = UIStoryboard(title: "Major", bundle: nil)
           if let newListView = storyboard.instantiateViewController(withIdentifier: "NewListView") as? NewListView {
               newListView.listName = selectedListName
               newListView.gadgets = selectedListItems ?? []
               navigationController?.pushViewController(newListView, animated: true)
           } else {
               print("No se pudo instanciar NewListView")
           }
       }
       
   }

Second View for displaying up components in listing:

import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase

class NewListView: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet weak var addItemTextFieldNew: UITextField!
    @IBOutlet weak var showListButton: UIButton!
    @IBOutlet weak var saveListButton: UIButton!
    @IBOutlet weak var plusButtonAdd: UIButton!
    @IBOutlet weak var newListTableView: UITableView!
    
    non-public let gradientLayer = CAGradientLayer()
    non-public let database = Database.database().reference(withPath: "iFoodList")
    non-public var listRef: DatabaseReference?
    var listName: String?
    var gadgets: [ListTextField] = []
    var lists: [String: [ListTextField]] = [:]

    
    override func viewDidLoad() {
        tremendous.viewDidLoad()
        
        guard let tableView = newListTableView else { return }
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(UINib(nibName: "NewListCell", bundle: nil), forCellReuseIdentifier: NewListCell.reuseIdentifier)
        tableView.estimatedRowHeight = 66
        tableView.rowHeight = UITableView.automaticDimension
        
        self.title = listName ?? "New Listing"
        view.backgroundColor = .white
        configureUI()
        loadListDataFromFirebase()

    }
    
    non-public func loadListDataFromFirebase() {
        guard let listName = listName else {
            print("Error: listName es nil")
            return
        }
        
        listRef = database.baby(listName)
        
        listRef?.observe(.worth, with: { snapshot in
            var newItems: [ListTextField] = []
            
            for baby in snapshot.youngsters {
                if let childSnapshot = baby as? DataSnapshot,
                   let listItem = ListTextField(snapshot: childSnapshot) {
                    newItems.append(listItem)
                } else {
                    print("Error al convertir el snapshot a ListTextField")
                }
            }
            
            self.gadgets = newItems
            DispatchQueue.primary.async {
                self.newListTableView.reloadData()
            }
        })
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        tremendous.viewWillDisappear(animated)
        listRef?.removeAllObservers()
    }


    override func viewDidLayoutSubviews() {
        tremendous.viewDidLayoutSubviews()
        gradientLayer.body = view.bounds
    }
    
    
    @IBAction func addPlusButton(_ sender: Any) {
        guard let newItemText = addItemTextFieldNew.textual content, !newItemText.isEmpty else {
            let alert = UIAlertController(
                title: NSLocalizedString("ERROR_TITLE", remark: ""),
                message: NSLocalizedString("EMPTY_FIELD_MESSAGE", remark: ""),
                preferredStyle: .alert
            )
            alert.addAction(UIAlertAction(
                title: NSLocalizedString("OK_BUTTON", remark: ""),
                model: .default,
                handler: nil)
            )
            current(alert, animated: true, completion: nil)
            return
        }
        
        // Verificar si el merchandise ya existe en la lista
        if gadgets.comprises(the place: { $0.title == newItemText }) {
            let alert = UIAlertController(
                title: NSLocalizedString("ERROR_TITLE", remark: ""),
                message: NSLocalizedString("ITEM_EXISTS_MESSAGE", remark: ""),
                preferredStyle: .alert
            )
            alert.addAction(UIAlertAction(
                title: NSLocalizedString("OK_BUTTON", remark: ""),
                model: .default,
                handler: nil)
            )
            current(alert, animated: true, completion: nil)
            return
        }
        
        let newItem = ListTextField(id: UUID().uuidString, title: newItemText, subtitle: "", isChecked: false)
        
        // Guardar el nuevo ítem en Firebase
        let listRef = database.baby(listName ?? "defaultListName")
        listRef.baby(newItem.id).setValue(newItem.toAnyObject())
        
        // Agregar el nuevo ítem a la lista native y actualizar la tabla
        gadgets.append(newItem)
        newListTableView.reloadData()
        addItemTextFieldNew.textual content = ""
    }
    
    @IBAction func saveListAction(_ sender: Any) {
        guard let listName = listName, !listName.trimmingCharacters(in: .whitespaces).isEmpty else {
            presentErrorAlert(message: NSLocalizedString("EMPTY_FIELD_MESSAGE", remark: ""))
            return
        }
        
        presentSaveAlert(listName: listName)
    }
    
    non-public func presentErrorAlert(message: String) {
        let alert = UIAlertController(
            title: NSLocalizedString("ERROR_TITLE", remark: ""),
            message: message,
            preferredStyle: .alert
        )
        
        alert.addAction(UIAlertAction(
            title: NSLocalizedString("OK", remark: ""),
            model: .default,
            handler: nil)
        )
        
        current(alert, animated: true, completion: nil)
    }
    
    non-public func presentSaveAlert(listName: String) {
        let alert = UIAlertController(
            title: NSLocalizedString("SAVE_ALERT_TITLE", remark: ""),
            message: NSLocalizedString("SAVE_ALERT_MESSAGE", remark: ""),
            preferredStyle: .alert
        )
        
        alert.addAction(UIAlertAction(
            title: NSLocalizedString("SAVE_ALERT_SAVE_BUTTON", remark: ""),
            model: .default,
            handler: { [weak self] _ in
                self?.saveDataInFirebase(listName: listName)
                self?.navigationController?.popViewController(animated: true)
            })
        )
        
        alert.addAction(UIAlertAction(
            title: NSLocalizedString("SAVE_ALERT_CANCEL_BUTTON", remark: ""),
            model: .cancel,
            handler: nil
        ))
        
        current(alert, animated: true, completion: nil)
    }
    
    func saveDataInFirebase(listName: String) {
        guard let uid = Auth.auth().currentUser?.uid else {
            print("No consumer is logged in.")
            return
        }

        // Aquí es donde estamos eliminando los espacios en blanco al principio y al closing de listName
        let listNameTrimmed = listName.trimmingCharacters(in: .whitespacesAndNewlines)
        let listRef = Database.database().reference().baby("userLists").baby(uid).baby(listNameTrimmed).baby("gadgets")

        var itemsData: [String: [String: Any]] = [:]
        for merchandise in gadgets {
            itemsData[item.id] = merchandise.toAnyObject() as? [String : Any]
        }
        print("ItemsData: (itemsData)")
        let dataToSave = ["items": itemsData]
        print("Information a guardar: (dataToSave)")
        listRef.updateChildValues(dataToSave) { (error, _) in
            if let error = error {
                print("Failed to save lots of information in Firebase: (error)")
            } else {
                print("Efficiently saved information in Firebase.")
            }
        }
    }
    
    @IBAction func showListAction(_ sender: Any) {
        let storyboard = UIStoryboard(title: "Major", bundle: nil)
        if let notePadVC = storyboard.instantiateViewController(withIdentifier: "NotePadView") as? NotePadView {
            notePadVC.listName = self.listName?.capitalized // Estás pasando el nombre de la lista aquí
            notePadVC.gadgets = self.gadgets // Necesitas pasar los ítems también
            navigationController?.pushViewController(notePadVC, animated: true)
        } else {
            print("No se pudo instanciar NotePadView")
        }
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
        return gadgets.rely
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("Creando celda NewListView para indexPath: (indexPath)")

        guard let cell = tableView.dequeueReusableCell(withIdentifier: NewListCell.reuseIdentifier, for: indexPath) as? NewListCell else {
            return UITableViewCell()
        }
        
        let nombreDeLaLista = listName ?? "defaultListName"
        cell.itemTextField.textual content = gadgets[indexPath.row].title
        cell.indexPath = indexPath
        
        cell.onEditAction = { [weak self] newItemTitle, newSubItemTitle, indexPath in
            guard let strongSelf = self, let indexPath = indexPath else { return }
            
            // Actualizar en Firebase
            strongSelf.database.baby("(nombreDeLaLista)/(strongSelf.gadgets[indexPath.row].id)/title").setValue(newItemTitle)
            
            // Actualizar la lista native
            strongSelf.gadgets[indexPath.row].title = newItemTitle
            
            // Actualizar la tabla
            tableView.reloadRows(at: [indexPath], with: .automated)
        }
        
        cell.onDeleteAction = { [weak self] indexPath in
            guard let strongSelf = self, let indexPath = indexPath else { return }
            
            let alert = UIAlertController(title: NSLocalizedString("Eliminar", remark: ""), message: NSLocalizedString("¿Estás seguro de que quieres eliminar este elemento?", remark: ""), preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: NSLocalizedString("Sí", remark: ""), model: .harmful, handler: { _ in
                
                // Borrar el elemento de Firebase
                strongSelf.database.baby("(nombreDeLaLista)/(strongSelf.gadgets[indexPath.row].id)").removeValue()
                
                // Borrar el elemento de la lista native
                strongSelf.gadgets.take away(at: indexPath.row)
                
                // Actualizar la tabla
                tableView.deleteRows(at: [indexPath], with: .automated)
            }))
            alert.addAction(UIAlertAction(title: NSLocalizedString("No", remark: ""), model: .cancel, handler: nil))
            strongSelf.current(alert, animated: true)
        }
        print("Celda NewListView creada con el título del elemento: (gadgets[indexPath.row].title)")

        return cell
    }

    
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let nombreDeLaLista = listName ?? "defaultListName"
        
        let deleteAction = UIContextualAction(model: .harmful, title: NSLocalizedString("Eliminar", remark: "")) { (motion, view, completion) in
            let alert = UIAlertController(title: NSLocalizedString("Eliminar", remark: ""), message: NSLocalizedString("¿Estás seguro de que quieres eliminar este elemento?", remark: ""), preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: NSLocalizedString("Sí", remark: ""), model: .harmful, handler: { _ in
                // Borrar el elemento de Firebase
                self.database.baby("(nombreDeLaLista)/(self.gadgets[indexPath.row].id)").removeValue()
                
                // Borrar el elemento de la lista native
                self.gadgets.take away(at: indexPath.row)
                
                // Actualizar la tabla
                tableView.deleteRows(at: [indexPath], with: .automated)
            }))
            alert.addAction(UIAlertAction(title: NSLocalizedString("No", remark: ""), model: .cancel, handler: nil))
            self.current(alert, animated: true)
            completion(true)
        }
        let configuration = UISwipeActionsConfiguration(actions: [deleteAction])
        return configuration
    }
    
    func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let nombreDeLaLista = listName ?? "defaultListName"
        let editAction = UIContextualAction(model: .regular, title: NSLocalizedString("Editar", remark: "")) { (motion, view, completion) in
            let alert = UIAlertController(title: NSLocalizedString("Editar", remark: ""), message: NSLocalizedString("Ingresa el nuevo valor.", remark: ""), preferredStyle: .alert)
            alert.addTextField { (textField) in
                textField.textual content = self.gadgets[indexPath.row].title
            }
            alert.addAction(UIAlertAction(title: NSLocalizedString("Actualizar", remark: ""), model: .default, handler: { _ in
                if let textField = alert.textFields?.first, let textual content = textField.textual content {
                    
                    // Actualizar en Firebase
                    self.database.baby("(nombreDeLaLista)/(self.gadgets[indexPath.row].id)/title").setValue(textual content)
                    
                    // Actualizar la lista native
                    self.gadgets[indexPath.row].title = textual content
                    
                    // Actualizar la tabla
                    tableView.reloadRows(at: [indexPath], with: .automated)
                }
            }))
            alert.addAction(UIAlertAction(title: NSLocalizedString("Cancelar", remark: ""), model: .cancel, handler: nil))
            self.current(alert, animated: true)
            completion(true)
        }
        editAction.backgroundColor = .blue
        let configuration = UISwipeActionsConfiguration(actions: [editAction])
        return configuration
    }
    
}
       struct ListTextField: Decodable {
           var id: String
           var title: String
           var subtitle: String
           var isChecked: Bool
           
           init(id: String, title: String, subtitle: String, isChecked: Bool) {
               self.id = id
               self.title = title
               self.subtitle = subtitle
               self.isChecked = isChecked
           }
           
           init?(snapshot: DataSnapshot) {
               guard let worth = snapshot.worth as? [String: AnyObject],
                     let id = worth["id"] as? String,
                     let title = worth["title"] as? String,
                     let subtitle = worth["subtitle"] as? String,
                     let isChecked = worth["isChecked"] as? Bool else {
                   return nil
               }
               
               self.id = id
               self.title = title
               self.subtitle = subtitle
               self.isChecked = isChecked
           }
           
           func toAnyObject() -> Any {
               return [
                   "id": id,
                   "title": title,
                   "subtitle": subtitle,
                   "isChecked": isChecked
               ]
           }
       }

Leave a Reply

Your email address will not be published. Required fields are marked *