1차적으로 지금까지 코딩한 파일을 전부 게시하겠습니다.
//
// UserModel.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 9. 9..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import UIKit
class UserModel: NSObject {
@objc var profileImageUrl: String?
@objc var userName: String?
@objc var uid: String?
}
//
// ChatModel.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 9. 10..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import ObjectMapper
class ChatModel: Mappable {
@objc public var users :Dictionary<String,Bool> = [:] //채팅방에 참여한 사람들
public var comments :Dictionary<String,Comment> = [:] //채팅방의 대화내용
required init?(map: Map) {
}
func mapping(map: Map) {
users <- map["users"]
comments <- map["comments"]
}
public class Comment :Mappable{
@objc public var uid : String?
@objc public var message : String?
public required init?(map: Map) {
}
public func mapping(map: Map) {
uid <- map["uid"]
message <- map["message"]
}
}
}
//
// AppDelegate.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 8. 30..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import Firebase
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
//
// ViewController.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 8. 30..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import UIKit
import SnapKit
import Firebase
class ViewController: UIViewController {
var box = UIImageView()
var remoteConfig : RemoteConfig!
override func viewDidLoad() {
super.viewDidLoad()
remoteConfig = RemoteConfig.remoteConfig()
let remoteConfigSettings = RemoteConfigSettings(developerModeEnabled: true)
remoteConfig.configSettings = remoteConfigSettings!
remoteConfig.setDefaults(fromPlist: "RemoteConfigDefaults")
remoteConfig.fetch(withExpirationDuration: TimeInterval(0)) { (status, error) -> Void in
if status == .success {
print("Config fetched!")
self.remoteConfig.activateFetched()
} else {
print("Config not fetched")
print("Error \(error!.localizedDescription)")
}
self.displayWelcome()
}
self.view.addSubview(box)
box.snp.makeConstraints { (make) in
make.center.equalTo(self.view)
}
box.image = imageLiteral(resourceName: "loading_icon")
}
func displayWelcome(){
let color = remoteConfig["splash_background"].stringValue
let caps = remoteConfig["splash_message_caps"].boolValue
let message = remoteConfig["splash_message"].stringValue
if(caps){
let alert = UIAlertController(title: "공지사항", message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "확인", style: UIAlertActionStyle.default, handler: { (action) in
exit(0)
}))
self.present(alert, animated: true, completion: nil)
}else{
let loginVC = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.present(loginVC, animated: false, completion: nil)
}
self.view.backgroundColor = UIColor(hex: color!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension UIColor {
convenience init(hex: String) {
let scanner = Scanner(string: hex)
scanner.scanLocation = 1
var rgbValue: UInt64 = 0
scanner.scanHexInt64(&rgbValue)
let r = (rgbValue & 0xff0000) >> 16
let g = (rgbValue & 0xff00) >> 8
let b = rgbValue & 0xff
self.init(
red: CGFloat(r) / 0xff,
green: CGFloat(g) / 0xff,
blue: CGFloat(b) / 0xff, alpha: 1
)
}
}
//
// LoginViewController.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 9. 5..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import UIKit
import Firebase
class LoginViewController: UIViewController {
@IBOutlet var email: UITextField!
@IBOutlet var password: UITextField!
@IBOutlet var loginButton: UIButton!
@IBOutlet var signup: UIButton!
let remoteConfig = RemoteConfig.remoteConfig()
var color : String!
override func viewDidLoad() {
super.viewDidLoad()
try! Auth.auth().signOut()
let statusBar = UIView()
self.view.addSubview(statusBar)
statusBar.snp.makeConstraints {(m) in
m.right.top.left.equalTo(self.view)
m.height.equalTo(20)
}
color = remoteConfig["splash_background"].stringValue
statusBar.backgroundColor = UIColor(hex: color)
loginButton.backgroundColor = UIColor(hex: color)
signup.backgroundColor = UIColor(hex: color)
loginButton.addTarget(self, action: #selector(logingEvent), for: .touchUpInside)
Auth.auth().addStateDidChangeListener{(auth, user) in
if(user != nil){
let view = self.storyboard?.instantiateViewController(withIdentifier: "MainViewTabBarController") as! UITabBarController
self.present(view, animated: true, completion: nil)
}
}
signup.addTarget(self, action: #selector(presentsSignup), for: .touchUpInside)
// Do any additional setup after loading the view.
}
@objc func logingEvent(){
Auth.auth().signIn(withEmail: email.text!, password: password.text!) {( user, err) in
if(err != nil) {
let alert = UIAlertController(title: "에러", message: err.debugDescription, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "확인",style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
@objc func presentsSignup(){
let view = self.storyboard?.instantiateViewController(withIdentifier: "SignupViewController") as! SignupViewController
self.present(view, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
//
// SignupViewController.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 9. 5..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import UIKit
import Firebase
class SignupViewController: UIViewController,UINavigationControllerDelegate,UIImagePickerControllerDelegate {
@IBOutlet var imageView: UIImageView!
@IBOutlet var email: UITextField!
@IBOutlet var name: UITextField!
@IBOutlet var password: UITextField!
@IBOutlet var signup: UIButton!
@IBOutlet var cancel: UIButton!
let remoteConfig = RemoteConfig.remoteConfig()
var color: String?
override func viewDidLoad() {
super.viewDidLoad()
let statusBar = UIView()
self.view.addSubview(statusBar)
statusBar.snp.makeConstraints {(m) in
m.right.top.left.equalTo(self.view)
m.height.equalTo(20)
}
color = remoteConfig["splash_background"].stringValue
statusBar.backgroundColor = UIColor(hex: color!)
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(imagePicker)))
signup.backgroundColor = UIColor(hex: color!)
cancel.backgroundColor = UIColor(hex: color!)
signup.addTarget(self, action: #selector(signupEvent), for: .touchUpInside)
cancel.addTarget(self, action: #selector(cancelevent), for: .touchUpInside)
// Do any additional setup after loading the view.
}
@objc func imagePicker(){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]){
imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
dismiss(animated: true, completion: nil)
}
@objc func signupEvent(){
Auth.auth().createUser(withEmail: email.text!, password: password.text!) {(user, err) in
let uid = user?.uid
let image = UIImageJPEGRepresentation(self.imageView.image!, 0.1)
Storage.storage().reference().child("userImages").child(uid!).putData(image!, metadata: nil, completion: { (data, error) in
let imageUrl = data?.downloadURL()?.absoluteString
let values = ["userName":self.name.text!,"profileImageUrl":imageUrl, "uid":Auth.auth().currentUser?.uid]
Database.database().reference().child("users").child(uid!).setValue(values, withCompletionBlock:
{ (err, ref) in
if(err==nil){
self.cancelevent()
}
})
})
}
}
@objc func cancelevent(){
self.dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
//
// MainViewController.swift -> PeopleViewController.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 9. 7..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import UIKit
import SnapKit
import Firebase
class PeopleViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var array : [UserModel] = []
var tableview : UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableview = UITableView()
tableview.delegate = self
tableview.dataSource = self
tableview.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
view.addSubview(tableview)
tableview.snp.makeConstraints { (m) in
m.top.equalTo(view)
m.bottom.left.right.equalTo(view)
}
Database.database().reference().child("users").observe(DataEventType.value, with: { (snapshot) in
self.array.removeAll()
let myUid = Auth.auth().currentUser?.uid
for child in snapshot.children {
let fchild = child as! DataSnapshot
let userModel = UserModel()
userModel.setValuesForKeys(fchild.value as! [String : Any])
if(userModel.uid == myUid){
continue
}
self.array.append(userModel)
}
DispatchQueue.main.async {
self.tableview.reloadData();
}
})
// Do any additional setup after loading the view.
}
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)
let imageview = UIImageView()
cell.addSubview(imageview)
imageview.snp.makeConstraints{(m) in
m.centerY.equalTo(cell)
m.left.equalTo(cell).offset(10)
m.height.width.equalTo(50)
}
URLSession.shared.dataTask(with: URL(string: array[indexPath.row].profileImageUrl!)!) { (data, response, err) in
DispatchQueue.main.async {
imageview.image = UIImage(data: data!)
imageview.layer.cornerRadius = imageview.frame.size.width/2
imageview.clipsToBounds = true
}
}.resume()
let label = UILabel()
cell.addSubview(label)
label.snp.makeConstraints{ (m) in
m.centerY.equalTo(cell)
m.left.equalTo(imageview.snp.right).offset(20)
}
label.text = array[indexPath.row].userName
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let view = self.storyboard?.instantiateViewController(withIdentifier: "ChatViewController") as? ChatViewController
view?.destinationUid = self.array[indexPath.row].uid
self.navigationController?.pushViewController(view!, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
//
// ChatViewController.swift
// FreeTalk
//
// Created by stayfoolish on 2018. 9. 10..
// Copyright © 2018년 stayfoolish. All rights reserved.
//
import UIKit
import Firebase
class ChatViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
@IBOutlet weak var tableview: UITableView!
@IBOutlet weak var textfield_message: UITextField!
@IBOutlet weak var sendButton: UIButton!
var uid : String?
var chatRoomUid : String?
var comments : [ChatModel.Comment] = []
var userModel :UserModel?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(self.comments[indexPath.row].uid == uid){
let view = tableView.dequeueReusableCell(withIdentifier: "MyMessageCell", for: indexPath) as! MyMessageCell
view.label_message.text = self.comments[indexPath.row].message
view.label_message.numberOfLines = 0
return view
}else{
let view = tableView.dequeueReusableCell(withIdentifier: "DestinationMessageCell", for: indexPath) as! DestinationMessageCell
view.label_name.text = userModel?.userName
view.label_message.text = self.comments[indexPath.row].message
view.label_message.numberOfLines = 0;
let url = URL(string:(self.userModel?.profileImageUrl)!)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, err) in
DispatchQueue.main.async {
view.imageview_profile.image = UIImage(data: data!)
view.imageview_profile.layer.cornerRadius = view.imageview_profile.frame.width/2
view.imageview_profile.clipsToBounds = true
}
}).resume()
return view
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
public var destinationUid :String? // 나중에 내가 채팅할 대상의 uid
override func viewDidLoad() {
super.viewDidLoad()
uid = Auth.auth().currentUser?.uid
sendButton.addTarget(self, action: #selector(createRoom), for: .touchUpInside)
checkChatRoom()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@objc func createRoom(){
let createRoomInfo : Dictionary<String,Any> = [ "users" : [
uid!: true,
destinationUid! :true
]
]
if(chatRoomUid == nil){
self.sendButton.isEnabled = false
// 방 생성 코드
Database.database().reference().child("chatrooms").childByAutoId().setValue(createRoomInfo, withCompletionBlock: { (err, ref) in
if(err == nil){
self.checkChatRoom()
}
})
}else{
let value :Dictionary<String,Any> = [
"uid" : uid!,
"message" : textfield_message.text!
]
Database.database().reference().child("chatrooms").child(chatRoomUid!).child("comments").childByAutoId().setValue(value)
}
}
func checkChatRoom(){
Database.database().reference().child("chatrooms").queryOrdered(byChild: "users/"+uid!).queryEqual(toValue: true).observeSingleEvent(of: DataEventType.value,with: { (datasnapshot) in
for item in datasnapshot.children.allObjects as! [DataSnapshot]{
if let chatRoomdic = item.value as? [String:AnyObject]{
let chatModel = ChatModel(JSON: chatRoomdic)
if(chatModel?.users[self.destinationUid!] == true){
self.chatRoomUid = item.key
self.sendButton.isEnabled = true
self.getDestinationInfo()
}
}
}
})
}
func getDestinationInfo(){
Database.database().reference().child("users").child(self.destinationUid!).observeSingleEvent(of: DataEventType.value, with: { (datasnapshot) in
self.userModel = UserModel()
self.userModel?.setValuesForKeys(datasnapshot.value as! [String:Any])
self.getMessageList()
})
}
func getMessageList(){
Database.database().reference().child("chatrooms").child(self.chatRoomUid!).child("comments").observe(DataEventType.value, with: { (datasnapshot) in
self.comments.removeAll()
for item in datasnapshot.children.allObjects as! [DataSnapshot]{
let comment = ChatModel.Comment(JSON: item.value as! [String:AnyObject])
self.comments.append(comment!)
}
self.tableview.reloadData()
})
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
class MyMessageCell: UITableViewCell{
@IBOutlet weak var label_message: UILabel!
}
class DestinationMessageCell: UITableViewCell{
@IBOutlet weak var imageview_profile: UIImageView!
@IBOutlet weak var label_message: UILabel!
@IBOutlet weak var label_name: UILabel!
}