Skip to content

Instantly share code, notes, and snippets.

@asciimike
Last active July 12, 2021 21:56
Show Gist options
  • Star 34 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save asciimike/cc45567cd95ba2a62017cb21e891effd to your computer and use it in GitHub Desktop.
Save asciimike/cc45567cd95ba2a62017cb21e891effd to your computer and use it in GitHub Desktop.
Zero to App: Develop with Firebase (for iOS - Google I/O 2016)
///
// AppDelegate.swift
// ZeroToApp
//
import UIKit
import Firebase
import FBSDKCoreKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Configure Firebase SDK
FIRApp.configure()
// Configure Facebook SDK
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
}
//
// ViewController.swift
// ZeroToApp
//
import UIKit
import Firebase
import FBSDKLoginKit
import Photos
struct ChatMessage {
var name: String!
var message: String!
var image: UIImage?
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// Outlets
@IBOutlet weak var messageTextField: UITextField!
@IBOutlet weak var sendButton: UIButton!
@IBOutlet weak var tableView: UITableView!
// Useful app properties
let imagePicker = UIImagePickerController()
var messages: [ChatMessage]!
var username: String!
// Firebase services
var database: FIRDatabase!
var auth: FIRAuth!
var storage: FIRStorage!
override func viewDidLoad() {
super.viewDidLoad()
// Initialize navigation bar
self.title = "Zero To App"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Log in",
style: UIBarButtonItemStyle.Plain,
target: self,
action: #selector(toggleAuthState))
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Camera,
target: self,
action: #selector(selectImage))
// Initialize send button
sendButton.addTarget(self,
action: #selector(sendMessage),
forControlEvents: .TouchUpInside)
// Initialize UIImagePicker
imagePicker.delegate = self
// Initialize other properties
messages = []
username = "iOS"
// Initialize UITableView
tableView.delegate = self
tableView.dataSource = self
let nib = UINib(nibName: "ChatMessageTableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "chatMessageCell")
// Initialize Database, Auth, Storage
database = FIRDatabase.database()
auth = FIRAuth.auth()
storage = FIRStorage.storage()
// Listen for when child nodes get added to the collection
let chatRef = database.reference().child("chat")
chatRef.observeEventType(.ChildAdded, withBlock: { (snapshot) -> Void in
// Get the chat message from the snapshot and add it to the UI
let data = snapshot.value as! Dictionary<String, String>
guard let name = data["name"] as String! else { return }
guard let message = data["message"] as String! else { return }
let chatMessage = ChatMessage(name: name, message: message, image: nil)
self.addMessage(chatMessage)
})
// Observe auth state change
self.auth.addAuthStateDidChangeListener { (auth, user) in
if (user != nil) {
self.username = user?.displayName
self.navigationItem.rightBarButtonItem?.title = "Log out"
} else {
self.username = "iOS"
self.navigationItem.rightBarButtonItem?.title = "Log in"
}
}
}
// Send a chat message
func sendMessage(sender: AnyObject) {
// Create chat message
let chatMessage = ChatMessage(name: self.username, message: messageTextField.text!, image: nil)
messageTextField.text = ""
// Create a reference to our chat message
let chatRef = database.reference().child("chat")
// Push the chat message to the database
chatRef.childByAutoId().setValue(["name": chatMessage.name, "message": chatMessage.message])
}
// Show a popup when the user asks to sign in
func toggleAuthState() {
if (auth.currentUser != nil) {
// Allow the user to sign out
do {
try auth.signOut()
} catch {}
} else {
// Log in to Facebook
let login = FBSDKLoginManager()
login.logInWithReadPermissions(["public_profile"], fromViewController: self, handler: { (result, error) in
if (error != nil || result.isCancelled) {
print(error)
} else {
// Log in to Firebase via Facebook
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(result.token.tokenString)
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
if (error != nil) {
print(error)
}
}
}
})
}
}
// Handle photo uploads button
func selectImage() {
imagePicker.allowsEditing = false
imagePicker.sourceType = .PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)
}
// pragma mark - UIImagePickerDelegate overrides
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
// Get local file URLs
guard let image: UIImage = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
let imageData = UIImagePNGRepresentation(image)!
guard let imageURL: NSURL = info[UIImagePickerControllerReferenceURL] as? NSURL else { return }
// Get a reference to the location where we'll store our photos
let photosRef = storage.reference().child("chat_photos")
// Get a reference to store the file at chat_photos/<FILENAME>
let photoRef = photosRef.child("\(NSUUID().UUIDString).png")
// Upload file to Firebase Storage
let metadata = FIRStorageMetadata()
metadata.contentType = "image/png"
photoRef.putData(imageData, metadata: metadata).observeStatus(.Success) { (snapshot) in
// When the image has successfully uploaded, we get it's download URL
let text = snapshot.metadata?.downloadURL()?.absoluteString
// Set the download URL to the message box, so that the user can send it to the database
self.messageTextField.text = text
}
// Clean up picker
dismissViewControllerAnimated(true, completion: nil)
}
func addMessage(var chatMessage: ChatMessage) {
// Handle remote image messages
if (chatMessage.message.containsString("https://firebasestorage.googleapis.com")) {
self.storage.referenceForURL(chatMessage.message).dataWithMaxSize(25 * 1024 * 1024, completion: { (data, error) -> Void in
let image = UIImage(data: data!)
chatMessage.image = image!
self.messages.append(chatMessage)
self.tableView.reloadData()
self.scrollToBottom()
})
// Handle asset library messages
} else if (chatMessage.message.containsString("assets-library://")) {
let assetURL = NSURL(string: chatMessage.message)
let assets = PHAsset.fetchAssetsWithALAssetURLs([assetURL!], options: nil)
let asset: PHAsset = assets.firstObject as! PHAsset
let manager = PHImageManager.defaultManager()
manager.requestImageForAsset(asset, targetSize: CGSize(width: 100.0, height: 100.0), contentMode: .AspectFit, options: nil, resultHandler: {(result, info)->Void in
chatMessage.image = result!
self.messages.append(chatMessage)
self.tableView.reloadData()
self.scrollToBottom()
})
// Handle regular messages
} else {
self.messages.append(chatMessage)
self.tableView.reloadData()
self.scrollToBottom()
}
}
func scrollToBottom() {
if (self.messages.count > 8) {
let bottomOffset = CGPoint(x: 0, y: tableView.contentSize.height - tableView.bounds.size.height)
tableView.setContentOffset(bottomOffset, animated: true)
}
}
// pragma mark - UITableViewDataSource overrides
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("chatMessageCell", forIndexPath: indexPath) as! ChatMessageTableViewCell
let chatMessage = messages[indexPath.row]
cell.nameLabel.text = chatMessage.name
cell.messageLabel.text = chatMessage.message
cell.photoView.image = chatMessage.image
return cell
}
// pragma mark - UITableViewDelegate overrides
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let chatMessage = messages[indexPath.row]
if (chatMessage.image != nil) {
return 345.0
} else {
return 58.0
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
// Create a chat message from a FIRDataSnapshot
func chatMessageFromSnapshot(snapshot: FIRDataSnapshot) -> ChatMessage? {
let data = snapshot.value as! Dictionary<String, String>
guard let name = data["name"] as String! else { return nil }
guard let message = data["message"] as String! else { return nil }
let chatMessage = ChatMessage(name: name, message: message, image: nil)
return chatMessage
}
}
@yannsonnboys
Copy link

Amazing

@aruld
Copy link

aruld commented Jun 25, 2016

I am seeing this error in Xcode 7.3.1. Any idea?
screen shot 2016-06-25 at 9 41 50 am

@rainyPoseidon
Copy link

ty this really help me

@Gokhansayilgan
Copy link

could you please share your ChatMessageTableViewCell class and your story board

@GodsEye-07
Copy link

GodsEye-07 commented Jun 19, 2018

@aruld this may be because there may be some possibel error in your ChatMessageTableViewCell or you might have forgot to create one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment