Post

Replies

Boosts

Views

Activity

Swift user online status updates but it repeats on cells that is not supposed to
I'm working on a chat app and I configured a function to check if a user is online. I'm able to see if another user is active or not, but, the issue I'm having is that if I scroll down (I'm using a UITableView) other users show as active and they are not. I placed the code inside the UITableViewCell class. Any suggestions as to what could be the problem are greatly appreciated. Here is my code: UITableViewCell `func configureHomeFeedCell(member: Member) { profileImage.loadImage(with: member.imageURL) profileName.text = "\(member.name)" + ", " + "\(member.age)" checkUserOnlineStatus(with: member.documentId) { _ in } } func checkUserOnlineStatus(with userId: String, completion: @escaping(Bool) -> Void) { let query = USERS_COLLECTION.document(userId).collection(IS_ONLINE) query.getDocuments { (snapshot, error) in if let error = error { print("ERROR..\(error.localizedDescription)") } else { snapshot?.documents.forEach({ diff in let isOnline = diff.get(USER_IS_ONLINE) as? Bool self.onlineViewStatus.backgroundColor = isOnline == true ? .green : .red completion(isOnline!) })}} query.addSnapshotListener { (snapshot, error) in snapshot?.documentChanges.forEach { diff in let isOnline = diff.document.get(USER_IS_ONLINE) as? Bool if (diff.type == .modified) { self.onlineViewStatus.backgroundColor = isOnline == true ? .green : .red completion(isOnline!) }}} }`
6
0
704
Jan ’23
push notifications open specific tab controller when the app is closed
Hi, I'm having a problem when opening a push notification to a specific tab when the app is closed/killed. The code below works properly when the app is in the background or in another tab. If closed and I open the push notification, the app opens to the main screen. Any ideas on how can I get it to open to the correct tab when is completely closed? any help is greatly appreciated.    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {              let scene = UIApplication.shared.connectedScenes.first             if let sceneDelegate = scene?.delegate as? SceneDelegate {               if let tabController = sceneDelegate.window?.rootViewController as? UITabBarController {                 tabController.selectedIndex = 1               }             } }
0
0
827
Nov ’22
Snapshot listener duplicating data
Hello, I'm working on this chat app and I have a snapshot listener to keep track the number of messages (with a badge) each user receives. I'm using a table view with pagination. The problem I'm having that I can't figure out is when a user gets a message, the table view duplicates the user, increases the badge number every time a message is received. Then, if i open the messages and then i go back to the first VC, there is another duplicate of the user but with no badge number because it was cleared. Any help is greatly appreciated. VC override func viewDidAppear(_ animated: Bool) {     super.viewDidAppear(animated)           fetchMatches()   } func fetchMatches() {     fetchInfo { matches in       self.match = matches       self.matchedMessagesTV.reloadData()     }   }       func fetchInfo(completion: @escaping([Match]) -> Void) {     if lastDocument == nil {       let query = MATCH_INFO_COLLECTION.document(currentUID!)         .collection("info").order(by: MATCH_TIMESTAMP, descending: false)       query.limit(to: 10).addSnapshotListener { (snapshot, error) in                   guard let last = snapshot?.documents.last else { return }         guard let snap = snapshot else { return }         snap.documentChanges.forEach({ diff in                       let dictionary = diff.document.data()           let memberId = dictionary[DOCUMENT_ID] as? String ?? ""           let memberAge = dictionary[AGE] as? Int ?? 0           let memberName = dictionary[FIRST_NAME] as? String ?? ""           let memberImageUrl = dictionary[PROFILE_IMAGE_URL] as? String ?? ""           let memberCurrentCity = dictionary[CURRENT_CITY] as? String ?? ""           let matchTimestamp = dictionary[MATCH_TIMESTAMP] as? Double ?? 0.0           let messageCounter = dictionary[MESSAGE_COUNTER] as? Int ?? 0                       let matches = Match(memberId: memberId, memberAge: memberAge ,memberName: memberName, memberImageUrl: memberImageUrl, memberCurrentCity: memberCurrentCity, matchTimestamp: Date(timeIntervalSince1970: matchTimestamp), messageCounter: messageCounter)                       self.match.append(matches)           self.memberId = matches.memberId           self.lastDocument = last           completion(self.match)         })       }     } else {       matchedMessagesTV.tableFooterView = createSpinnerFooter()       let query = MATCH_INFO_COLLECTION.document(currentUID!)         .collection("info").order(by: MATCH_TIMESTAMP, descending: false)               DispatchQueue.main.async {         self.matchedMessagesTV.tableFooterView = nil       }       query.start(afterDocument: self.lastDocument!)         .limit(to: 10).addSnapshotListener { (snapshot, error) in                       guard let last = snapshot?.documents.last else { return }           guard let snap = snapshot else { return }           snap.documentChanges.forEach({ diff in                           let dictionary = diff.document.data()             let memberId = dictionary[DOCUMENT_ID] as? String ?? ""             let memberAge = dictionary[AGE] as? Int ?? 0             let memberName = dictionary[FIRST_NAME] as? String ?? ""             let memberImageUrl = dictionary[PROFILE_IMAGE_URL] as? String ?? ""             let memberCurrentCity = dictionary[CURRENT_CITY] as? String ?? ""             let matchTimestamp = dictionary[MATCH_TIMESTAMP] as? Double ?? 0.0             let messageCounter = dictionary[MESSAGE_COUNTER] as? Int ?? 0                           let matches = Match(memberId: memberId, memberAge: memberAge ,memberName: memberName, memberImageUrl: memberImageUrl, memberCurrentCity: memberCurrentCity, matchTimestamp: Date(timeIntervalSince1970: matchTimestamp), messageCounter: messageCounter)                           self.match.append(matches)             self.memberId = matches.memberId             self.lastDocument = last             completion(self.match)                         })         }}   } class Match {       var memberId: String   let memberAge: Int   let memberName: String   let memberImageUrl: String   let memberCurrentCity: String   let matchTimestamp: Date!   let messageCounter: Int       init(memberId: String, memberAge: Int, memberName: String, memberImageUrl: String, memberCurrentCity: String, matchTimestamp: Date, messageCounter: Int) {           self.memberId = memberId     self.memberAge = memberAge     self.memberName = memberName     self.memberImageUrl = memberImageUrl     self.memberCurrentCity = memberCurrentCity     self.matchTimestamp = matchTimestamp     self.messageCounter = messageCounter   } }
3
0
611
Dec ’21
Zoom in/out an image inside of a table view
I'm trying to replicate the image zoom in/out feature we find in IG, the only issue I'm having is when I zoom-in, the image is not covering the entire screen, it only zooms-in inside the cell. This is a regular setup, a table view, a cell, an image view and a label. I'm not sure what I'm missing here. Any help is greatly appreciated: View Controller import UIKit class ViewController: UIViewController, UITableViewDelegate { @IBOutlet weak var tableView: UITableView! var picArray = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self tableView.delegate = self tableView.rowHeight = 300 } } extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return picArray.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! cell let data = picArray[indexPath.item] cell.backgroundColor = .red cell.setupCell(image: data) cell.clipsToBounds = false cell.selectionStyle = .none return cell } } Cell Class import UIKit class cell: UITableViewCell, UIScrollViewDelegate { @IBOutlet var picture: UIImageView! @IBOutlet var caption: UILabel! var zoomEnabled = false var imgCenter:CGPoint? override func awakeFromNib() { super.awakeFromNib() picture.contentMode = .scaleAspectFill picture.isUserInteractionEnabled = true picture.clipsToBounds = false caption.layer.zPosition = -1 let pinch = UIPinchGestureRecognizer(target: self, action: #selector(self.pinch(sender:))) pinch.delegate = self self.picture.addGestureRecognizer(pinch) let pan = UIPanGestureRecognizer(target: self, action: #selector(self.pan(sender:))) pan.delegate = self self.picture.addGestureRecognizer(pan) } override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } @objc func pan(sender: UIPanGestureRecognizer) { if self.zoomEnabled && sender.state == .began { self.imgCenter = sender.view?.center } else if self.zoomEnabled && sender.state == .changed { let translation = sender.translation(in: self) if let view = sender.view { view.center = CGPoint(x:view.center.x + translation.x, y:view.center.y + translation.y) } sender.setTranslation(CGPoint.zero, in: self.picture.superview) } } @objc func pinch(sender: UIPinchGestureRecognizer) { if sender.state == .began { let currentScale = self.picture.frame.size.width / self.picture.bounds.size.width let newScale = currentScale * sender.scale if newScale > 1 { self.zoomEnabled = true } } else if sender.state == .changed { guard let view = sender.view else {return} let pinchCenter = CGPoint(x: sender.location(in: view).x - view.bounds.midX, y: sender.location(in: view).y - view.bounds.midY) let transform = view.transform.translatedBy(x: pinchCenter.x, y: pinchCenter.y) .scaledBy(x: sender.scale, y: sender.scale) .translatedBy(x: -pinchCenter.x, y: -pinchCenter.y) let currentScale = self.picture.frame.size.width / self.picture.bounds.size.width var newScale = currentScale * sender.scale if newScale < 1 { newScale = 1 let transform = CGAffineTransform(scaleX: newScale, y: newScale) self.picture.transform = transform sender.scale = 1 }else { view.transform = transform sender.scale = 1 } } else if sender.state == .ended { guard let center = self.imgCenter else {return} UIView.animate(withDuration: 0.3, animations: { self.picture.transform = CGAffineTransform.identity self.picture.center = center }, completion: { _ in self.zoomEnabled = false }) } } func setupCell(image: String) { if let image : UIImage = UIImage(named: image) { picture.image = image } } }
0
0
1.2k
Nov ’21
UITableView reload not working
Hello, I'm working on this messaging app where users have the option of blocking other users. The problem I'm having is reloading the UITableView after a user has been blocked. The first block of code is to block the users: MemberVC func blockUserOption(forMember memberData: String, userHasBeenBlocked: Bool, completion: ((Error?) -> Void)?) {     BLOCKED_USERS_COLLECTION.document(currentUID!).getDocument { (snapshot, error) in       let data = [self.memberDocumentID: userHasBeenBlocked]       if snapshot?.exists == true {         BLOCKED_USERS_COLLECTION.document(self.currentUID!).updateData(data)       } else {         BLOCKED_USERS_COLLECTION.document(self.currentUID!).setData(data)       }}} //Here is how I'm executing the code above:        let blockUser = UIAlertAction(title: "Block", style: .default) { (action) in         let alert = UIAlertController(title: "Block", message: "Are you sure you want to block" + " " + "\(self.memberName as Any)?", preferredStyle: .alert)         alert.view.tintColor = .brick                   alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (action: UIAlertAction) in           self.blockUserOption(forMember: self.memberDocumentID, userHasBeenBlocked: true, completion: nil)            self.userDefaults.setValue("yes", forKey: RELOAD)         }))         alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action: UIAlertAction!) in         }))         self.present(alert, animated: true, completion: nil)       } Once the user has been blocked, the current view controller gets dismissed and the user goes back to the view controller where the table view needs to reload and remove the blocked user from the list. MemberListVC    override func viewDidAppear(_ animated: Bool) {     super.viewDidAppear(true)     let reloadQuery = userDefaults.string(forKey: RELOAD)           if reloadQuery == "yes" {               self.match.removeAll()               let query = MATCH_INFO_COLLECTION.document(currentUID!)         .collection("info").order(by: TIMESTAMP, descending: false)               query.limit(to: 10).getDocuments { (snapshot, error) in               self.filterUsersThatWereBlocked { blockedUsers in                 guard let last = snapshot?.documents.last else { return }                 guard let snap = snapshot else { return }                 snap.documents.forEach({ document in                                       let data = document.data()                   let memberId = data[DOCUMENT_ID] as? String ?? ""                   let memberAge = data[AGE] as? Int ?? 0                   let memberName = data[FIRST_NAME] as? String ?? ""                   let memberImageUrl = data[PROFILE_IMAGE_URL] as? String ?? ""                   let memberCurrentCity = data[CURRENT_CITY] as? String ?? ""                   let timestamp = data[TIMESTAMP] as? Double ?? 0.0                                       let matches = Match(memberId: memberId, memberAge: memberAge ,memberName: memberName, memberImageUrl: memberImageUrl, memberCurrentCity: memberCurrentCity, matchTimestamp: Date(timeIntervalSince1970: timestamp))                                       guard matches.memberId != Auth.auth().currentUser?.uid else { return }                   guard blockedUsers[matches.memberId] == nil else { return }                                       self.match.append(matches)                                       self.matchedMessagesTV.reloadData()                 })                 self.lastDocument = last               }       }       userDefaults.setValue("no", forKey: RELOAD)     } else {       print("NOTHING TO DO HERE")     }   }    func filterUsersThatWereBlocked(completion: @escaping([String: Bool]) -> Void) {     guard let currentUid = Auth.auth().currentUser?.uid else { return }     BLOCKED_USERS_COLLECTION.document(currentUid).getDocument { (snapshot, error) in       guard let data = snapshot?.data() as? [String: Bool] else {         completion([String: Bool]())         return       }       completion(data)     }} Now, if I close and re-open the app, the users that were blocked, do not show up. I'm not sure if the issue is because I'm trying to reload the view inside "viewDidAppear", I tried with "viewWillAppear" and the outcome is the same. Any help is greatly appreciated. Thank you!
13
0
1.8k
Oct ’21
UITableView refresh issue
Hello, I'm working on an app that is fetching data from Firebase and the data is loaded in a UITableView. I'm using pagination (loading 3 posts at a time). Users are allowed to delete their own post. The issue I'm having is when the user deletes the post (first from Firebase and then from the array), the tableView removes the user's post, but it also removes (from the view only) the next 2 posts. Then all I see are the next 3 posts and if I scroll up to see the previous ones, the app crashes because the indexPath.row is out of range. Below is my code. Any help is greatly appreciated: override func viewDidLoad() {     super.viewDidLoad()          configureUI()     fetchGlimpseData()     configureRefreshControl()   }    func configureRefreshControl() {     let refreshControl = UIRefreshControl()     refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)     glimpseTableView?.refreshControl = refreshControl   }       private func createSpinnerFooter() -> UIView {     let footerView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 100))     let spinner = UIActivityIndicatorView()     spinner.center = footerView.center     spinner.color = .brick     footerView.addSubview(spinner)     spinner.startAnimating()           return footerView   }  @objc func handleRefresh() {     glimpse.removeAll(keepingCapacity: false)     self.currentKey = nil     fetchGlimpseData()   } func fetchGlimpseData() {       if lastDocument == nil {         GLIMPSE_ALL_USERS_DATA.order(by: TIMESTAMP, descending: true).limit(to: 3)           .getDocuments { [self] (snapshot, error) in.... //this block of code works properly else {         glimpseTableView.tableFooterView = createSpinnerFooter()                   GLIMPSE_ALL_USERS_DATA.order(by: TIMESTAMP, descending: true).start(afterDocument: lastDocument!).limit(to: 3)           .getDocuments { [self] (snapshot, error ) in.......//this block of code works properly    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {     let position = scrollView.contentOffset.y     let maxOffset = scrollView.contentSize.height - scrollView.frame.size.height     if maxOffset - position <= 50 {       fetchGlimpseData()     }} func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {     return glimpse.count   }       func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {     let gCell = glimpseTableView.dequeueReusableCell(withIdentifier: "GlimpseCell", for: indexPath) as! GlimpseCell           gCell.delegateProfilePic = self     gCell.delegateGlimpseZoom = self     gCell.delegateGlimpseOption = self     gCell.configureGlimpseCell(glimpse: glimpse[indexPath.row])     gCell.separatorInset = .init(top: 5, left: 0, bottom: 5, right: 0)     gCell.backgroundColor = .beige     gCell.layer.borderWidth = 1     gCell.layer.borderColor = UIColor.gray.cgColor     gCell.selectionStyle = .none           return gCell   }       func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {     return .delete   }   func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {     return false   }   func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {     guard editingStyle == .delete else { return }     glimpseTableView.beginUpdates()     glimpse.remove(at: indexPath.row)     glimpseTableView.deleteRows(at: [indexPath], with: .automatic)     glimpseTableView.reloadData()     glimpseTableView.endUpdates()   }
5
0
1.1k
Sep ’21
UITableView display first 5 rows of an array
I have a UITableView with 1 cell and when the array loads I just want for the user to see the content of the first 5 rows and blur the rest. So, if there is an array with 20 items, the first 5 need to be visible and the remaining 15 with a blur. With the code below, I'm able to just add a blur to row 5 only, I can't figure this out. Any help is greatly appreciated. let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light)) func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) - Int { return array.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) - UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell cell.cellLbl?.text = array[indexPath.row] if indexPath.row == 5 { visualEffectView.frame = cell.bounds visualEffectView.layer.masksToBounds = true cell.addSubview(visualEffectView) } return cell }
2
0
1.2k
May ’21