I am working on incorporating a chat feature in my app and everything is working smoothly using JSQMessagesViewController except that I can't get the navigation bar to show in the view controller. I have tried almost everything it seems like but it seems to be hidden by the view or something although I am not sure of this. Here is my code for the Conversation view controller:
import UIKit
import JSQMessagesViewController
import Firebase
import AVKit
class ConvoVC: JSQMessagesViewController {
var chatRoomId = Variables.chatRoomID
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
var messages = [JSQMessage]()
override func viewDidLoad() {
super.viewDidLoad()
senderId = uid!
senderDisplayName = uid!
let factory = JSQMessagesBubbleImageFactory()
incomingBubbleImageView = factory?.incomingMessagesBubbleImage(with: UIColor.jsq_messageBubbleLightGray())
outgoingBubbleImageView = factory?.outgoingMessagesBubbleImage(with: UIColor.jsq_messageBubbleBlue())
collectionView.collectionViewLayout.incomingAvatarViewSize = CGSize.zero
collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSize.zero
let query = ref.child("ChatRooms").child(chatRoomId!).child("Messages").queryLimited(toLast: 10)
query.observe(.childAdded, with: { (snapshot) in
if snapshot.exists(){
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
self.messages.append(message)
self.finishReceivingMessage()
}
}
}
})
//let navigationBar = UINavigationBar(frame: CGRect(0, 0, self.view.frame.size.width, 64)) // Offset by 20 pixels vertically to take the status bar into account
//navigationBar.backgroundColor = UIColor.white
//navigationBar.delegate = self as! UINavigationBarDelegate
// Create a navigation item with a title
//let navigationItem = UINavigationItem()
//navigationItem.title = contacts[i].firstName
// Create right button for navigation item
setupBackButton()
// Make the navigation bar a subview of the current view controller
//self.view.addSubview(navigationBar)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
self.navigationController?.isNavigationBarHidden = false
}
func setupBackButton() {
let backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(backButtonTapped))
navigationItem.leftBarButtonItem = backButton
}
#objc func backButtonTapped() {
dismiss(animated: true, completion: nil)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell
let message = messages[indexPath.item]
if message.senderId == senderId {
cell.textView!.textColor = UIColor.white
} else {
cell.textView!.textColor = UIColor.black
}
return cell
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageDataForItemAt indexPath: IndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return messages.count
}
override func didPressSend(_ button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: Date!) {
let messageRef = ref.child("ChatRooms").child(chatRoomId!).child("Messages").childByAutoId()
let message = ["sender_id": senderId, "name": senderDisplayName, "text": text]
messageRef.setValue(message)
finishSendingMessage()
JSQSystemSoundPlayer.jsq_playMessageSentSound()
self.finishSendingMessage()
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAt indexPath: IndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = messages[indexPath.item]
if message.senderId == senderId {
return outgoingBubbleImageView
}else {
return incomingBubbleImageView
}
}
}
Here is the code for the didSelectRow method in the class that comes before the conversation view controller:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let chatFunctions = ChatFunctions()
ref.child("users").child(uid!).observeSingleEvent(of: .value) { (snapshot) in
let userOne = User(snapshot: snapshot)
self.chatRoomIdentity = chatFunctions.startChat(user1: userOne , user2: self.matches[indexPath.row])
self.senderDisName = self.matches[indexPath.row].firstName
Variables.chatRoomID = self.chatRoomIdentity
self.present(ConvoVC(), animated: true, completion: nil)
}
}
Thanks in advance!
You are presenting it modally on this line which would present it full screen (so no navigation bar):
self.present(ConvoVC(), animated: true, completion: nil)
Push it onto the navigation stack instead like this:
self.navigationController?.pushViewController(ConvoVC(), animated: true)
If you don't have your first controller set as the root view controller of a navigation controller, make sure to do so beforehand.
Either that or set ConvoVC as a root view controller of a navigation controller and present that navigation controller
self.present(navigationController, animated: true, completion: nil).
The first solution will let you pop the ConvoVC and back to the previous view controller via the navigation bar, whereas the latter will not (you would have to dismiss it).
I highly recommend reading up on iOS navigation & segues as it's a core aspect of any iOS application.
Related
I'm trying to add a new NSTextView to the last index in my collection view every time the attributed string exceeds a certain bounds. The code works perfectly until the 5th item then it starts its starts creating an item every time the enter button is pressed. I'm thinking its a bug but im not sure. if any one can show me a better way to do it or improve the current code I have I would appreciate it. Below is my code:
Here is the CollectionViewItem
class DocumentItem: NSCollectionViewItem {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
self.itemView?.wantsLayer = true
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
}
func getView() -> DocumentTextView {
return self.itemView!
}
}
Here is the collectionView datasource
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return DocList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "DocumentItem"), for: indexPath)
return item
}
Here is the NSTextView subclass
class DocumentTextView: NSTextView {
var theContainer = NSTextContainer()
var theStorage = NSTextStorage()
var theManager = NSLayoutManager()
var table = NSTextTable()
var pdfPage: PDFPage?
override init(frame frameRect: NSRect) {
super.init(frame: NSRect(origin: frameRect.origin, size: NSSize(width: 800, height: 1131 )), textContainer: theContainer)
theStorage.addLayoutManager(theManager)
theManager.addTextContainer(theContainer)
self.textContainerInset = CGSize(width: 50, height: 50)
self.textContainer?.widthTracksTextView = true
self.textContainer?.heightTracksTextView = true
self.textContainer?.lineBreakMode = .byWordWrapping
self.maxSize = NSSize(width: 800, height: 1131)
self.backgroundColor = NSColor.fromHexString("ffffff")!
self.isRichText = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is the function bringing the bug
func textDidChange(_ notification: Notification) {
var textView = notification.object as? DocumentTextView
let numberOfItems = theDocumentOutlineView.numberOfItems(inSection: 0)
let theLastTextView = theDocumentOutlineView.item(at: numberOfItems - 1) as! DocumentItem
if textView == theLastTextView.itemView {
print(textView?.attributedString().size())
if (textView?.attributedString().size().height)! >= 1106.0 {
self.DocList.append(2)
var set = Set<IndexPath>()
set.insert(NSIndexPath(forItem: self.DocList.count - 1 , inSection: 0) as IndexPath)
theDocumentOutlineView.insertItems(at: set)
theDocumentOutlineView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
var newFirstResponder = theDocumentOutlineView.item(at: self.DocList.count - 1) as! DocumentItem
newFirstResponder.itemView?.delegate = self
self.view.window?.makeFirstResponder(newFirstResponder.itemView)
}
}
}
Here's my test project, maybe it helps. The delegate of the text view is its view controller, the NSCollectionViewItem. The view controller of the collection view also receives NSText.didChangeNotification notifications to check the length of the text. heightTracksTextView of the text container is false.
ViewController:
class ViewController: NSViewController, NSCollectionViewDataSource, NSCollectionViewDelegate {
#IBOutlet weak var collectionView: NSCollectionView!
var docList: [DocumentObject] = [DocumentObject(index: 0, string: NSAttributedString(string: "New 0"))]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(DocumentItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"))
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange),
name: NSText.didChangeNotification, object: nil)
}
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return docList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
if let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"),
for: indexPath) as? DocumentItem {
item.representedObject = docList[indexPath.item]
return item
}
return NSCollectionViewItem()
}
#objc func textDidChange(_ notification: Notification) {
if let textView = notification.object as? NSTextView {
if let theLastItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem,
textView === theLastItem.itemView {
//if textView.attributedString().size().height >= 1106.0 {
print("\(textView.attributedString().size().height) \(textView.layoutManager!.usedRect(for: textView.textContainer!).size.height)")
if let textContainer = textView.textContainer,
let heigth = textView.layoutManager?.usedRect(for: textContainer).size.height,
heigth >= 1106.0 {
DispatchQueue.main.async {
if let window = self.view.window,
window.makeFirstResponder(nil) { // end editing of previous item
self.docList.append(DocumentObject(index: self.docList.count - 1, string: NSAttributedString(string: "New \(self.docList.count)")))
let set: Set = [IndexPath(item: self.docList.count - 1, section: 0)]
self.collectionView.insertItems(at: set)
self.collectionView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
if let newItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem {
window.makeFirstResponder(newItem.itemView)
}
}
}
}
}
}
}
}
DocumentItem:
class DocumentItem: NSCollectionViewItem, NSTextViewDelegate {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
self.itemView?.delegate = self
}
override var representedObject: Any? {
didSet {
if let item = representedObject as? DocumentObject {
itemView?.textStorage?.setAttributedString(item.string)
}
}
}
func textDidEndEditing(_ notification: Notification) {
if let item = representedObject as? DocumentObject {
item.string = itemView?.textStorage?.copy() as! NSAttributedString
}
}
}
DocumentObject:
class DocumentObject {
var index: Int
var string: NSAttributedString
init(index: Int, string: NSAttributedString) {
self.index = index
self.string = string
}
}
I have a collection view controller. In collectionView cell I have label which I made clickable to push to the nextViewController.
I know that problem in navigationController. But I'm new in swift so can't fix. Hope you guys can help me.
Here's my SceneDelegate:
let layout = UICollectionViewFlowLayout()
// Create the root view controller as needed
let nc = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
let win = UIWindow(windowScene: winScene)
win.rootViewController = nc
win.makeKeyAndVisible()
window = win
and my label:
let text = UILabel()
text.text = "something"
text.isUserInteractionEnabled = true
self.addSubview(text)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(PopularCellTwo.labelTapped))
text.addGestureRecognizer(gestureRecognizer)
}
#objc func labelTapped() {
let nextVC = NextViewController()
self.navigationController?.pushViewController(nextVC, animated: true)
print("labelTapped tapped")
}
I also added screenshot. When I click on "Something" It should go next page.
[1]: https://i.stack.imgur.com/4oYwb.png
You can use delegate or closure to do this
class ItemCollectionViewCell: UICollectionViewCell {
var onTapGesture: (() -> ())?
}
Then in your function you do
#objc func labelTapped() {
onTapGesture?()
}
And in your controller
class HomeController: UICollectionViewController {
//...
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = // dequeue cell
cell.onTapGesture = { [unowned self] in
let nextVC = NextViewController()
self.navigationController?.pushViewController(nextVC, animated: true)
}
return cell
}
}
self.navigationController?.pushViewController(nextVC, animated: true)
what self are you referring to ? because you cant make push in child class
you have HomeController i assume its your parent controller .
just try to debug what self is this could attempt by debugging or debug by condition
print (self)
if (self.isKind(of: YourParentController.self)) {
// make push
}
or try to check , see if navigationcontroller somehow has nil value
Here is how you do it using closures. I've created a closure parameter in UICollectionViewCell sub-class. When the label gesture target is hit I call the closure which then executed the navigation in HomeController.
class HomeController: UICollectionViewController {
//...
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = // dequeue cell
cell.labelTap = { [weak self] in
guard let self = self else { return }
let nextVC = NextViewController()
self.navigationController?.pushViewController(nextVC, animated: true)
print("navigated")
}
return cell
}
}
class CollectionViewCell: UICollectionViewCell {
var labelTap: (() -> Void)?
#objc func labelTapped() {
print("labelTapped tapped")
labelTap?()
}
}
What I want to achieve?
I have 2 UITableViewController : AddCardVC and ListDeckController. I want to pass selected Deck in ListDeckController to AddCardVC then updateUI on AddCardVC
My code: (I'm building on Swift 5, iOS 13)
ListDeckController.swift:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let addCardVC = storyboard.instantiateViewController(withIdentifier: "AddCard") as? AddCardVC {
if let deck = allDecks?[indexPath.row] {
addCardVC.selectedDeck = deck
}
}
self.navigationController?.popViewController(animated: true)
}
AddCardVC.swift:
var selectedDeck: Deck?
{
didSet {
viewWillAppear(true)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let deck = selectedDeck {
//Update UI
self.chooseDeckButton.setTitle(deck.name, for: .normal)
print(chooseDeckButton.titleLabel?.text ?? "")
self.tableView.reloadData()
}
}
What happend?
After I got selected Deck in AddCardVC, the console print out chooseDeckButton.titleLabel?.text = "My Deck" which is what I want. But The button title on UI is "Choose your deck"
Console image Button on UI
So, why the setButtonTitle not showing on UI in my case?
Thank you for your time
First, create a protocol for DeckDelegate
protocol SelectedDeckDelegate {
func didSelectDeck(selectedDeck : Deck)
}
Now in your ListDeckController.swift, implement the delegate
var deckDelegate : SelectedDeckDelegate?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if let deck = allDecks?[indexPath.row] {
deckDelegate?.didSelectDeck(selectedDeck: deck)
self.navigationController?.popViewController(animated: true)
} else {
print("deck is empty")
}
}
And in your AddCardVC, when navigating to ListDeckController, assign the delegate to self
// Make AddCardVC conform to SelectedDeckDelegate
class AddCardVC : UIViewController, SelectedDeckDelegate {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let deck = selectedDeck {
//Update UI
self.chooseDeckButton.setTitle(deck.name, for: .normal)
print(chooseDeckButton.titleLabel?.text ?? "")
self.tableView.reloadData()
}
}
// assign the delegate to self here
#IBAction func selectDeckBtnAction(_ sender : Any) {
let vc = storyboard.instantiateViewController(withIdentifier: "ListDeckController") as? ListDeckController
vc.deckDelegate = self
self.navigationController?.pushViewController(vc, animated: true)
}
// this will get called whenever selectedDeck is updated from ListDeckController
func didSelectDeck(selectedDeck: Deck) {
self.selectedDeck = selectedDeck
chooseDeckButton.setTitle(selectedDeck.name , for: .normal)
}
}
I want to use the same objects of one ViewController for saving into Firebase and for fetching saved data to preview and update if necessary.
Initially I used textfield in static cells it worked pretty well, but fail to insert text in textfield in dynamic cell.
When I call print function for the textfield in console it prints out correct value, but doesn't show anything on screen of simulator. I even tried to use simple strait text string to put it into textfield, but unsuccessful.
here is related code from TextMessageViewController, which i use for sending data to Firebase through textfields in dynamical tablecells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TextInputTableViewCell = receiverEmailTableView.dequeueReusableCell(withIdentifier: "ReceiverEmail") as! TextInputTableViewCell!
cell.recepientEmailTF.delegate = self
cell.recepientEmailTF.tag = indexPath.row
return cell
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
if MyGlobalVariables.emails.count <= 3 {
print("tag master = \(textField.tag)")
switch textField.tag {
case 0:
if MyGlobalVariables.emails.endIndex == 0 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[0] = textField.text!
case 1:
if MyGlobalVariables.emails.endIndex == 1 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[1] = textField.text!
case 2:
if MyGlobalVariables.emails.endIndex == 2 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[2] = textField.text!
default:
print("exceeded")
}
DispatchQueue.main.async {
self.receiverEmailTableView.reloadData()
}
} else {
print("exceeded emails limit, add alert")
}
}
Portion of code from TextPreviewViewController from where I want to get firebase data and add it to texfields. This viewcontroller is connected to preview viewcontroller in storyboard
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let edit = UITableViewRowAction(style: .default, title: "Edit") { (action, indexPath) in
let newMessageVC = self.storyboard?.instantiateViewController(withIdentifier: "TextMessage") as? TextMessageViewController
newMessageVC?.modalPresentationStyle = .overCurrentContext
self.present(newMessageVC!, animated: true, completion: {
let updateButton = newMessageVC?.saveOrUpdateButton
updateButton?.titleLabel?.text = "Update"
let messageBody = newMessageVC?.messageTV
let dateField = newMessageVC?.tergetDateTF
let action = MyGlobalVariables.refMessages.child(MyGlobalVariables.uidUser!)
// CONCERN POINT: from here->
let cell1: TextInputTableViewCell = newMessageVC?.receiverEmailTableView.dequeueReusableCell(withIdentifier: "ReceiverEmail") as! TextInputTableViewCell!
cell1.recepientEmailTF.delegate = self
cell1.recepientEmailTF.allowsEditingTextAttributes = true
let texfielf = cell1.recepientEmailTF
MyGlobalVariables.emails.removeAll()
MyGlobalVariables.emails = ["","",""]
// cell1.recepientEmailTF.text = "Suka blyat" <- even this simple text doesnt appear
MyGlobalVariables.emails[0].append(self.messages[indexPath.row].email1!)
texfielf?.text = MyGlobalVariables.emails[0]
//cell1.recepientEmailTF.text = MyGlobalVariables.emails[0] <- this code also doesnt work
MyGlobalVariables.emails[1].append(self.messages[indexPath.row].email2!)
texfielf?.text = self.messages[indexPath.row].email2!
MyGlobalVariables.emails[2].append(self.messages[indexPath.row].email3!)
texfielf?.text = self.messages[indexPath.row].email3!
DispatchQueue.main.async {
newMessageVC?.receiverEmailTableView.reloadData()
}
//CONCERN POINT: ->up to here
messageBody?.text = self.messages[indexPath.row].message!
dateField?.text = self.messages[indexPath.row].setupDate!
if let autoID2 = self.messages[indexPath.row].autoID {
MyGlobalVariables.messageForUpdate1.append(autoID2) }
})
}
return [edit]
}
My UITableViewCell class
public class TextInputTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var recepientEmailTF: UITextField!
override public func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override public func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}}
I would appreciate any help or advices.
recently in the search VC of my app I have been having a major problem with the contraints for weeks. I've redone them 4 times now with no improvement. My tableview cell is not complex -- an imageView located at the left and two labels on top of each other. Most cells size fine. The only thing is that(without pattern) two cells are randomly messed up(the labels and imageView move way out of place). You can see here:
Here is a picture of the constraints for the vc:
The strange thing is that this sometimes occurs when I toggle the scopeButtons up top. I looked in my code to see if I could fix this when the scopeButton reloads the tableview, but I could not find a problematic instance. My code is below:
import UIKit
import Firebase
import Kingfisher
class SearchPostsController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
var idArray:[String] = []
var detailViewController: DetailViewController? = nil
var candies = [Person]()
var filteredCandies = [Person]()
let searchController = UISearchController(searchResultsController: nil)
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = false
//initiate the search bar that appears up top when view is segued to
}
if let selectionIndexPath = self.tableView.indexPathForSelectedRow {
self.tableView.deselectRow(at: selectionIndexPath, animated: animated)
}
self.tableView.reloadData()
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
Database.database().reference()
.child("\(UserData().mySchool!)/posts")
.queryOrderedByKey()//keys were out of order, so we have to use this to help
.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.childrenCount)
for child in snapshot.children.allObjects as! [DataSnapshot] {
print(child.key)
self.idArray.append(child.key)
}
var reversedNames = [String]()
for arrayIndex in 0..<self.idArray.count {
reversedNames.append(self.idArray[(self.idArray.count - 1) - arrayIndex])
//reverse names so we dont have to sort the cells by date
}
for x in reversedNames{
self.searchNames(id: x)//get names from the ids here, tada!!!
self.tableView.reloadData()
}
})
//self.tableView.reloadData()//without this, the results wouldnt show up right away
searchController.searchBar.setScopeBarButtonTitleTextAttributes([NSAttributedStringKey.foregroundColor.rawValue: UIColor.white], for: .normal)
searchController.searchBar.scopeButtonTitles = ["Posts", "Users"]
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search posts or usernames"
searchController.searchBar.showsScopeBar = true
navigationItem.searchController = searchController
definesPresentationContext = true
if let splitViewController = splitViewController {
let controllers = splitViewController.viewControllers
detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 74
}
// override func viewWillDisappear(_ animated: Bool) {
// candies.removeAll()
// }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DAY69:GRADUATION DAY", for: indexPath) as! SeachCell
cell.cellImageVIew.frame.size.width = 48
cell.cellImageVIew.frame.size.height = 48
let personUser: Person
if isFiltering() {
personUser = filteredCandies[indexPath.row]
} else {
personUser = candies[indexPath.row]
}
//PERSON USER IS IMPORTANT!!!!! ^^^
cell.nameLabel.text = personUser.name.removingPercentEncoding
cell.messageLabel.text = personUser.category.removingPercentEncoding
let name = personUser.name
Database.database().reference().child("users/\(name)/profileImageURL").observe(.value, with: { (snapshot) in
let profURL = "\(snapshot.value!)"
let profIRL = URL(string: profURL)
//set up imageview
cell.cellImageVIew.layer.borderWidth = 1
cell.cellImageVIew.layer.masksToBounds = false
cell.cellImageVIew.layer.borderColor = UIColor.black.cgColor
cell.cellImageVIew.layer.cornerRadius = cell.cellImageVIew.frame.height/2
cell.cellImageVIew.clipsToBounds = true
cell.cellImageVIew.contentMode = .scaleAspectFill
cell.cellImageVIew.kf.indicatorType = .activity
cell.cellImageVIew.kf.setImage(with: profIRL)
})
//TODO: make an extension of imageview to do all this for me. It's getting to be ridiculous
return cell
}
func searchNames(id: String){
// var message = String()
// var name = String()
Database.database().reference().child("\(UserData().mySchool!)/posts/\(id)/message").observe(.value, with: { (snapshot) in
// message = snapshot.value as! String
Database.database().reference().child("\(UserData().mySchool!)/posts").child("\(id)/username").observe(.value, with: { (username) in
// name = username.value as! String
let user = Person(category: "\(snapshot.value!)", name: "\(username.value!)", id: id)
self.candies.append(user)
print( "\(snapshot.value!)", "\(username.value!)")
self.tableView.reloadData()
})
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering() {
return filteredCandies.count
}
return candies.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
tableView.estimatedRowHeight = 74.0
tableView.rowHeight = UITableViewAutomaticDimension
return UITableViewAutomaticDimension
}
// func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
// return 74
// }
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "DAY69:GRADUATION DAY", for: indexPath) as! SeachCell
cell.cellImageVIew.frame.size.width = 48
cell.cellImageVIew.frame.size.height = 48
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles?[searchBar.selectedScopeButtonIndex]
if scope == "Users"{
let username = candies[indexPath.row].name
print(username)
self.tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "userClicked", sender: username)
}
if scope == "Posts"{
let post = candies[indexPath.row].category
let user = candies[indexPath.row].name
let id = candies[indexPath.row].id
print(post)
let defaults = UserDefaults.standard
defaults.set(id, forKey: "ID")
let def2 = UserDefaults.standard
def2.set(post, forKey: "Post")
def2.set(user, forKey: "USER")
self.tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "postCellTapped", sender: nil)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//__________tbv methods above________________________________________________
func searchBarIsEmpty() -> Bool {
// Returns true if the text is empty or nil
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredCandies = candies.filter({(candy : Person) -> Bool in
let doesCategoryMatch = (scope == "Posts") || (scope == "Users")
print(searchText)
if searchBarIsEmpty() {
return doesCategoryMatch
}
if scope == "Users"{
return doesCategoryMatch && candy.name.lowercased().contains(searchText.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!.lowercased())
}
else{
return doesCategoryMatch && candy.category.lowercased().contains(searchText.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!.lowercased())
}
})
tableView.reloadData()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let personalUser: Person
if isFiltering() {
personalUser = filteredCandies[indexPath.row]
} else {
personalUser = candies[indexPath.row]
}
}
}
if segue.identifier == "userClicked" {
if let nextView = segue.destination as? UserProfileController {
nextView.selectedUser = "\(sender!)"
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func isFiltering() -> Bool {
let searchBarScopeIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
return searchController.isActive && (!searchBarIsEmpty() || searchBarScopeIsFiltering)
}
}
extension SearchPostsController: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
}
extension SearchPostsController: UISearchBarDelegate {
// MARK: - UISearchBar Delegate
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
Any help would be greatly appreciated in trying to fix the constraints! Thanks!