Skip to content

Instantly share code, notes, and snippets.

@asciimike
Last active July 12, 2021 21:56
Show Gist options
  • Save asciimike/cc45567cd95ba2a62017cb21e891effd to your computer and use it in GitHub Desktop.
Save asciimike/cc45567cd95ba2a62017cb21e891effd to your computer and use it in GitHub Desktop.

Revisions

  1. asciimike revised this gist May 21, 2016. No changes.
  2. asciimike revised this gist May 21, 2016. 3 changed files with 30 additions and 113 deletions.
    30 changes: 30 additions & 0 deletions AppDelegate.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    ///
    // 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)
    }

    }

    2 changes: 0 additions & 2 deletions ViewController.swift
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,6 @@
    // ViewController.swift
    // ZeroToApp
    //
    // Copyright © 2016 Google. All rights reserved.
    //

    import UIKit
    import Firebase
    111 changes: 0 additions & 111 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,111 +0,0 @@
    <!-- Zero to App -->
    <!-- Copyright © 2016 Google. All rights reserved. -->
    <html>
    <head>
    <script src="https://www.gstatic.com/firebasejs/3.0.0/firebase.js"></script>
    <title>ZeroToApp</title>
    <style>
    #messages { width: 40em; border: 1px solid grey; min-height: 20em; }
    #messages img { max-width: 240px; max-height: 160px; display: block; }
    #header { position: fixed; top: 0; background-color: white; }
    .push { margin-bottom: 2em; }
    @keyframes yellow-fade { 0% {background: #f2f2b8 <span class='hexPreview' style='background-color: #f2f2b8'>&nbsp;</span>;} 100% {background: none;} }
    .highlight { -webkit-animation: yellow-fade 2s ease-in 1; animation: yellow-fade 2s ease-in 1; }
    </style>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
    // Step 0: HTML defined, variables for elements
    var messagesList = document.getElementById('messages'),
    textInput = document.getElementById('text'),
    sendButton = document.getElementById('send'),
    login = document.getElementById('login'),
    googleLogin = document.getElementById('google'),
    facebookLogin = document.getElementById('facebook'),
    signedIn = document.getElementById('loggedin'),
    logout = document.getElementById('logout'),
    usernameElm = document.getElementById('username'),
    password = document.getElementById('password'),
    username = "Web";
    var config = {
    apiKey: "<your-api-key>",
    authDomain: "<your-auth-domain>",
    databaseURL: "<your-database-url>",
    storageBucket: "<your-storage-bucket>"
    };
    sendButton.addEventListener('click', function(evt) {
    var chat = { name: username, message: textInput.value };
    addMessage(chat);
    textInput.value = '';
    });
    function handleFileSelect(e) {
    var file = e.target.files[0];
    var reader = new FileReader();
    reader.onload = (function(theFile) {
    return function(e) {
    addMessage({ name: "Web", message: e.target.result });
    };
    })(file);
    reader.readAsDataURL(file);
    }
    file.addEventListener('change', handleFileSelect, false);
    function setUsername(newUsername) {
    if (newUsername == null) {
    newUsername = "Web";
    }
    console.log(newUsername);
    username = newUsername;
    var isLoggedIn = username != 'Web';
    usernameElm.innerText = newUsername;
    logout.style.display = isLoggedIn ? '' : 'none';
    facebookLogin.style.display = isLoggedIn ? 'none' : '';
    googleLogin.style.display = isLoggedIn ? 'none' : '';
    }
    function addMessage(chat) {
    var li = document.createElement('li');
    var nameElm = document.createElement('h4');
    nameElm.innerText = chat.name;
    li.appendChild(nameElm);
    li.className = 'highlight';
    if ( chat.message.indexOf("https://firebasestorage.googleapis.com/") == 0
    || chat.message.indexOf("https://lh3.googleusercontent.com/") == 0
    || chat.message.indexOf("http://pbs.twimg.com/") == 0
    || chat.message.indexOf("data:image/") == 0) {
    var imgElm = document.createElement("img");
    imgElm.src = chat.message;
    li.appendChild(imgElm);
    }
    else {
    var messageElm = document.createElement("span");
    messageElm.innerText = chat.message;
    li.appendChild(messageElm);
    }
    messagesList.appendChild(li);
    li.scrollIntoView(false);
    sendButton.scrollIntoView(false);
    }
    //window.app = app; // NOTE: just for debugging
    //for (var i=0; i < 10; i++) addMessage({ name: "Web", message: ''+i });
    setUsername('Web');
    });
    </script>
    </head>
    <body>
    <div id='header'>
    <label for='username'><img src="https://www.gstatic.com/images/icons/material/system/1x/account_box_black_24dp.png" width="24"/></label>
    <span id='username'></span>
    <span id='login'>
    <button id='google' class='idp-button'>Sign in with Google</button>
    <button id='facebook' class='idp-button'>Sign in with Facebook</button>
    </span>
    <button id='logout' class='idp-button'>Sign out</button>
    </div>
    <div class="push"></div>
    <ul id='messages'></ul>
    <div id='footer'>
    <img src="https://www.gstatic.com/images/icons/material/system/1x/add_a_photo_black_24dp.png" width="24"/>
    <input type="file" id="file" name="file" />
    <input id='text'></text>
    <button id='send'>Send</button>
    </div>
    </body>
    </html>
  3. asciimike revised this gist May 21, 2016. 1 changed file with 111 additions and 0 deletions.
    111 changes: 111 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,111 @@
    <!-- Zero to App -->
    <!-- Copyright © 2016 Google. All rights reserved. -->
    <html>
    <head>
    <script src="https://www.gstatic.com/firebasejs/3.0.0/firebase.js"></script>
    <title>ZeroToApp</title>
    <style>
    #messages { width: 40em; border: 1px solid grey; min-height: 20em; }
    #messages img { max-width: 240px; max-height: 160px; display: block; }
    #header { position: fixed; top: 0; background-color: white; }
    .push { margin-bottom: 2em; }
    @keyframes yellow-fade { 0% {background: #f2f2b8 <span class='hexPreview' style='background-color: #f2f2b8'>&nbsp;</span>;} 100% {background: none;} }
    .highlight { -webkit-animation: yellow-fade 2s ease-in 1; animation: yellow-fade 2s ease-in 1; }
    </style>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
    // Step 0: HTML defined, variables for elements
    var messagesList = document.getElementById('messages'),
    textInput = document.getElementById('text'),
    sendButton = document.getElementById('send'),
    login = document.getElementById('login'),
    googleLogin = document.getElementById('google'),
    facebookLogin = document.getElementById('facebook'),
    signedIn = document.getElementById('loggedin'),
    logout = document.getElementById('logout'),
    usernameElm = document.getElementById('username'),
    password = document.getElementById('password'),
    username = "Web";
    var config = {
    apiKey: "<your-api-key>",
    authDomain: "<your-auth-domain>",
    databaseURL: "<your-database-url>",
    storageBucket: "<your-storage-bucket>"
    };
    sendButton.addEventListener('click', function(evt) {
    var chat = { name: username, message: textInput.value };
    addMessage(chat);
    textInput.value = '';
    });
    function handleFileSelect(e) {
    var file = e.target.files[0];
    var reader = new FileReader();
    reader.onload = (function(theFile) {
    return function(e) {
    addMessage({ name: "Web", message: e.target.result });
    };
    })(file);
    reader.readAsDataURL(file);
    }
    file.addEventListener('change', handleFileSelect, false);
    function setUsername(newUsername) {
    if (newUsername == null) {
    newUsername = "Web";
    }
    console.log(newUsername);
    username = newUsername;
    var isLoggedIn = username != 'Web';
    usernameElm.innerText = newUsername;
    logout.style.display = isLoggedIn ? '' : 'none';
    facebookLogin.style.display = isLoggedIn ? 'none' : '';
    googleLogin.style.display = isLoggedIn ? 'none' : '';
    }
    function addMessage(chat) {
    var li = document.createElement('li');
    var nameElm = document.createElement('h4');
    nameElm.innerText = chat.name;
    li.appendChild(nameElm);
    li.className = 'highlight';
    if ( chat.message.indexOf("https://firebasestorage.googleapis.com/") == 0
    || chat.message.indexOf("https://lh3.googleusercontent.com/") == 0
    || chat.message.indexOf("http://pbs.twimg.com/") == 0
    || chat.message.indexOf("data:image/") == 0) {
    var imgElm = document.createElement("img");
    imgElm.src = chat.message;
    li.appendChild(imgElm);
    }
    else {
    var messageElm = document.createElement("span");
    messageElm.innerText = chat.message;
    li.appendChild(messageElm);
    }
    messagesList.appendChild(li);
    li.scrollIntoView(false);
    sendButton.scrollIntoView(false);
    }
    //window.app = app; // NOTE: just for debugging
    //for (var i=0; i < 10; i++) addMessage({ name: "Web", message: ''+i });
    setUsername('Web');
    });
    </script>
    </head>
    <body>
    <div id='header'>
    <label for='username'><img src="https://www.gstatic.com/images/icons/material/system/1x/account_box_black_24dp.png" width="24"/></label>
    <span id='username'></span>
    <span id='login'>
    <button id='google' class='idp-button'>Sign in with Google</button>
    <button id='facebook' class='idp-button'>Sign in with Facebook</button>
    </span>
    <button id='logout' class='idp-button'>Sign out</button>
    </div>
    <div class="push"></div>
    <ul id='messages'></ul>
    <div id='footer'>
    <img src="https://www.gstatic.com/images/icons/material/system/1x/add_a_photo_black_24dp.png" width="24"/>
    <input type="file" id="file" name="file" />
    <input id='text'></text>
    <button id='send'>Send</button>
    </div>
    </body>
    </html>
  4. asciimike created this gist May 21, 2016.
    250 changes: 250 additions & 0 deletions ViewController.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,250 @@
    //
    // ViewController.swift
    // ZeroToApp
    //
    // Copyright © 2016 Google. All rights reserved.
    //

    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
    }
    }