Skip to content

Instantly share code, notes, and snippets.

@dilipiOSDeveloper
Last active September 11, 2018 05:43
Show Gist options
  • Save dilipiOSDeveloper/893d653154f07b18c7c90e987346c1b3 to your computer and use it in GitHub Desktop.
Save dilipiOSDeveloper/893d653154f07b18c7c90e987346c1b3 to your computer and use it in GitHub Desktop.
//
// ChatViewController.swift
// pukkading
//
// Created by Vikas Pundora on 23/07/18.
// Copyright © 2018 Twist. All rights reserved.
//
import UIKit
import SystemConfiguration
import Foundation
import JSQMessagesViewController
import SDWebImage
import MobileCoreServices
import Alamofire
class ChatViewController: JSQMessagesViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
var timer = Timer() // Timer
var listId:String?
var receivedId:String?
var listName:String?
var messages = [MyMessage]()
var avatars = [String: JSQMessagesAvatarImage]()
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
var strImage = [UIImage]()
let picker = UIImagePickerController()
var parentNavigationController: UINavigationController?
var stringID = String()
var userValueStore:String!
var shopKeeperValueStore:String?
//var staticTextArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
if (!self.isInternetAvailable()){
self.alertMessageShow(title: "No Internet Connection", message: "Make sure your device is connected to the internet.")
}
else{
GIFHUD.shared.setGif(named: "pika.gif")
GIFHUD.shared.show()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3), execute: {
GIFHUD.shared.dismiss(completion: {
})
})
//self.userValueStore = ""
self.senderId = "1"
self.senderDisplayName = "Sender"
picker.delegate = self
self.edgesForExtendedLayout = []
self.collectionView?.collectionViewLayout.sectionInset = UIEdgeInsets(top: 60, left: 0, bottom: 0, right: 0)
self.inputToolbar?.contentView?.textView.placeHolder = "Type a message..."
self.inputToolbar?.contentView?.textView.returnKeyType = UIReturnKeyType.done
self.inputToolbar?.contentView?.textView.autocorrectionType = .no
collectionView?.collectionViewLayout.incomingAvatarViewSize = .zero
collectionView?.collectionViewLayout.outgoingAvatarViewSize = .zero
addHeaderView()
setupBubbles()
chatMessageShow()
automaticallyScrollsToMostRecentMessage = true
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(updateChat), userInfo: nil, repeats: true)
}
}
override func viewDidDisappear(_ animated: Bool) {
//timer.invalidate()
}
func updateChat(){
userMessageAfterParticularMessages()
}
func addHeaderView() {
let selectableView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 60))
selectableView.backgroundColor = UIColor(red: 0.149, green: 0.1529, blue: 0.2, alpha: 1.0)
let btn: UIButton = UIButton(frame: CGRect(x: 8, y: 13, width: 50, height: 50))
btn.setTitle("Back", for: .normal)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
btn.addTarget(self, action: #selector(backButtonAction), for: .touchUpInside)
selectableView.addSubview(btn)
let lblListTitle = UILabel(frame: CGRect(x:btn.frame.size.width + 10 ,y:24,width: selectableView.frame.size.width - 100, height: 18))
lblListTitle.textColor = UIColor.white
lblListTitle.textAlignment = .center
lblListTitle.font = UIFont.boldSystemFont(ofSize: 16)
lblListTitle.text = listName
selectableView.addSubview(lblListTitle)
view.addSubview(selectableView)
}
func backButtonAction(){
timer.invalidate()
_ = navigationController?.popViewController(animated: true)
}
private func setupBubbles() {
let factory = JSQMessagesBubbleImageFactory()
outgoingBubbleImageView = factory?.outgoingMessagesBubbleImage(with: UIColor.jsq_messageBubbleBlue())
incomingBubbleImageView = factory?.incomingMessagesBubbleImage(with: UIColor.jsq_messageBubbleGreen())
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, attributedTextForCellTopLabelAt indexPath: IndexPath) -> NSAttributedString? {
let message = messages[indexPath.item]
if indexPath.item == 0 {
return NSAttributedString(string:message.date.dateString(), attributes:
[NSForegroundColorAttributeName: UIColor.lightGray,
NSFontAttributeName: UIFont.boldSystemFont(ofSize: 13.0)])
}else {
let previousMessage = messages[indexPath.item - 1]
if Calendar.current.isDate(previousMessage.date, inSameDayAs: message.date) {
return nil
}else {
return NSAttributedString(string:message.date.dateString(), attributes:
[NSForegroundColorAttributeName: UIColor.lightGray,
NSFontAttributeName: UIFont.boldSystemFont(ofSize: 13.0)])
}
}
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForCellTopLabelAt indexPath: IndexPath) -> CGFloat {
let message = messages[indexPath.item]
if indexPath.item == 0 {
return kJSQMessagesCollectionViewCellLabelHeightDefault
}else {
let previousMessage = messages[indexPath.item - 1]
if Calendar.current.isDate(previousMessage.date, inSameDayAs: message.date) {
return 0.0
}else {
return kJSQMessagesCollectionViewCellLabelHeightDefault
}
}
}
// Showing outgoing bubble based on sender id
override func collectionView(_ collectionView: JSQMessagesCollectionView, messageBubbleImageDataForItemAt indexPath: IndexPath) -> JSQMessageBubbleImageDataSource {
let message = messages[indexPath.item]
if message.senderId == "1" {
return outgoingBubbleImageView
} else {
return incomingBubbleImageView
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("Array Count : \(messages.count)")
return messages.count
}
override func collectionView(_ collectionView: JSQMessagesCollectionView!, messageDataForItemAt indexPath: IndexPath!) -> JSQMessageData!{
return messages[indexPath.item]
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell
let message = self.messages[indexPath.item]
let dateFormat = DateFormatter()
dateFormat.dateFormat = "h:mm a"
let strDate: String = dateFormat.string(from: (message.date)!)
cell.cellBottomLabel.text = strDate
let topdate = DateFormatter()
topdate.dateStyle = .medium
topdate.doesRelativeDateFormatting = true
let dateString = topdate.string(from: message.date)
cell.cellTopLabel.text = dateString
return cell
}
override func didPressSend(_ button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: Date!){
sendMessageToOtherUser(with: text)//
//self.staticTextArray.append(text)
self.messages.append(MyMessage(senderId: senderId, senderDisplayName: senderDisplayName, date: date, text: text, messageID:""))
// this shows on chat screen same time after sending
self.finishSendingMessage(animated: true)
self.view.endEditing(true)
}
override func didPressAccessoryButton(_ sender: UIButton!) {
print("didPressAccessoryButton")
let alert = UIAlertController(title: "Media Message", message: "Please Select A Media", preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: {(alert : UIAlertAction) in
self.view.endEditing(true)
})
let photos = UIAlertAction(title: "Photos", style: .default, handler: {(alert : UIAlertAction) in
self.chooseMedia(type: kUTTypeImage)
})
alert.addAction(cancel)
alert.addAction(photos)
present(alert, animated: true, completion: nil)
}
override func collectionView(_ collectionView: JSQMessagesCollectionView, didTapMessageBubbleAt indexPath: IndexPath) {
let message: JSQMessage? = messages[indexPath.item]
if message?.isMediaMessage != nil {
let mediaItem: JSQMessageMediaData? = message?.media
if (mediaItem is JSQPhotoMediaItem) {
print("Tapped photo message bubble!")
let photoItem = mediaItem as? JSQPhotoMediaItem
let newImageView = UIImageView(image: photoItem?.image)
newImageView.frame = UIScreen.main.bounds
newImageView.backgroundColor = UIColor.black.withAlphaComponent(0.8)
newImageView.contentMode = .scaleToFill
newImageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(dismissFullscreenImage))
newImageView.addGestureRecognizer(tap)
self.view.addSubview(newImageView)
self.tabBarController?.tabBar.isHidden = true
}
}
}
func dismissFullscreenImage(_ sender: UITapGestureRecognizer) {
self.tabBarController?.tabBar.isHidden = false
sender.view?.removeFromSuperview()
}
override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
let msgID = messages[indexPath.item]
print("Message ID : \(msgID.messageID)")
if(msgID.senderId == "1"){
if (action == #selector(UIResponderStandardEditActions.delete(_:))) {
self.messages.remove(at: indexPath.item)
self.deleteOwnerMessage(with: "\(msgID.messageID)")
print("Message After Delete : \(messages)")
}
}
}
// Image Picker Functions
private func chooseMedia(type: CFString){
picker.mediaTypes = [type as String]
present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
DispatchQueue.main.async { () -> Void in
if let pic = info[UIImagePickerControllerOriginalImage] as? UIImage{
self.strImage.append(pic)
//let img = JSQPhotoMediaItem(image: pic)
//let date = Date()
self.sendImageToOtherUser()
//self.messages.append(MyMessage(senderId: "1", senderDisplayName: self.senderDisplayName, date: date, media: img!, messageID: self.stringID))
self.finishSendingMessage(animated: true)
}
self.dismiss(animated: true, completion: nil)
}
}
// end Picker
override func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == "\n" {
self.view.endEditing(true)
}
return true
}
// diliptest 1234 business user , user id - 1929 , deal id - 29861 author id - 1910
// User Message Page after perticular message for a Perticular Listing
func userMessageAfterParticularMessages(){
let prs = [
"user_id":Current_User.ID,
"receiver_id":receivedId,
"deal_id":listId,
"msg_id":userValueStore,
"user_listing_after_msg": "1" as String
]
Service.StartWithoutLoading(prs as [String : AnyObject]?, onCompletion: { result in
print("RESPONSE JSON :\(result)")
if let status_value = result["status"] as? String{
if(status_value == "success"){
guard let message_array = result["message"] as? [[String:AnyObject]] else{return}
for messageData in message_array{
let msg_ID = messageData["id"] as? String
let self_Message = messageData["is_self"] as? String
let is_attachment = messageData["is_attachment"] as? String
let msg_text = messageData["message"] as? String
let added_time = messageData["added_time"]
guard let timeinterval : TimeInterval = (added_time)?.doubleValue else{return}
let dateFromServer = NSDate(timeIntervalSince1970:timeinterval)
let dateFormater : DateFormatter = DateFormatter()
dateFormater.dateFormat = "dd-MMM-yyyy hh:mm a"
let shopkeeper = UserDefaults.standard.object(forKey: "shopkeeper_name") as? String // shopkeeper
let user = UserDefaults.standard.object(forKey: "user_image") as? String // other user
DispatchQueue.main.async {
let photo = JSQPhotoMediaItem()
if(self_Message == "1"){
if is_attachment == "0"{
self.messages.removeLast()
let message = MyMessage(senderId: self_Message!, senderDisplayName: shopkeeper!, date: dateFromServer as Date, text: msg_text!, messageID: msg_ID!)
self.messages.append(message)
self.finishReceivingMessage(animated: true)
}
else{
if let url = NSURL(string:msg_text! ){
guard let data = NSData(contentsOf: url as URL) else{ return }
let image = UIImage(data: data as Data)
photo.image = image
photo.appliesMediaViewMaskAsOutgoing = true
let message = MyMessage(senderId: self_Message!, senderDisplayName: shopkeeper!, date: dateFromServer as Date!, media: photo, messageID: msg_ID!)
self.messages.append(message)
self.finishReceivingMessage(animated: true)
}
}
}
else{
if is_attachment == "0"{
//self.messages.removeLast()
let message = MyMessage(senderId: "0", senderDisplayName: user!, date: dateFromServer as Date, text: msg_text!, messageID: msg_ID!)
self.messages.append(message)
self.finishReceivingMessage(animated: true)
}
else{
if let url = NSURL(string:msg_text! ){
guard let data = NSData(contentsOf: url as URL) else{ return }
let image = UIImage(data: data as Data)
photo.image = image
photo.appliesMediaViewMaskAsOutgoing = true
let message = MyMessage(senderId: "0", senderDisplayName: user!, date: dateFromServer as Date!, media: photo, messageID: msg_ID!)
self.messages.append(message)
self.finishReceivingMessage(animated: true)
}
}
}
}
}
let id = message_array.last?["id"]
print("last message id \(id)")
self.userValueStore = id as! String!
}
else{
print(status_value as Any)
}
}
})
}
// delete own message based on message id
func deleteOwnerMessage(with messageID:String){
let prs = [
"msg_id":messageID,
"send_msg_delete_self": "1" as String
]
print("Message ID Passed for Delete API : \(messageID)")
Service.StartWithoutLoading(prs as [String : AnyObject]?, onCompletion: { result in
print("JSON Response :\(result)")
DispatchQueue.global(qos: .background).async {
let json = result as? [String:AnyObject]
DispatchQueue.main.async {
if let sq = json?["status"] as? String{
if (sq == "success"){
print("Shopkeeper message deleted successfully.")
self.collectionView.reloadData()
}
else{
self.showAlertWithTitle("Error", message: "Cannot delete the received message.")
print("Error in deleting deal")
}
}
}
}
})
}
// delete message web service
// {"status":"success","message_id":1269,"result":"Message sent successfully"}
// Send Message to other user
func sendMessageToOtherUser(with messageSend:String){
let prs = [
"author_id":Current_User.ID,
"receiver_id":receivedId,
"deal_id":listId,
"message":messageSend,
"send_msg_to_other": "1" as String
]
Alamofire.upload(
multipartFormData: { MultipartFormData in
for (key, value) in prs {
MultipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
}, to: URL.App_URL) { (result) in
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
print(response.result.value as Any)
if let jsonDict = response.result.value as? [String:AnyObject],
let status = jsonDict["status"] as? String {
DispatchQueue.main.async {
if (status == "success"){
let idMessage = jsonDict["message_id"] as? Int
//self.userValueStore = "\(idMessage!)"
}
else{
self.showAlertWithTitle("Failed", message: "Error while sending message.")
}
}
}
}
case .failure(let encodingError):
print(encodingError)
DispatchQueue.main.async {
let alertView = UIAlertView(title: "Error", message: "Server is not responding properly.", delegate: nil, cancelButtonTitle: "Try Again")
alertView.alertViewStyle = .default
alertView.show()
}
break
}
}
}
func sendImageToOtherUser(){
let prs = [
"author_id":Current_User.ID,
"receiver_id":receivedId,
"deal_id":listId,
"send_msg_to_other": "1" as String
]
Alamofire.upload(
multipartFormData: { MultipartFormData in
for (key, value) in prs {
MultipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
for element in 0..<self.strImage.count {
let singleImage : Data? = self.strImage[element].lowestQualityJPEGNSData as Data?
MultipartFormData.append(singleImage!, withName: "image", fileName: "swift_file.jpg", mimeType: "image/jpeg")
}
}, to: URL.App_URL) { (result) in
switch result {
case .success(let upload, _, _):
upload.responseJSON { response in
print(response.result.value as Any)
if let jsonDict = response.result.value as? [String:AnyObject],
let status = jsonDict["status"] as? String {
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
if (status == "success"){
_ = jsonDict["message_id"] as? Int
//self.stringID = "\(idMessage!)"
}
else{
self.showAlertWithTitle("Failed", message: "Error while sending message.")
}
}
}
}
}
case .failure(let encodingError):
print(encodingError)
DispatchQueue.global(qos: .background).async {
let alertView = UIAlertView(title: "Error", message: "Server is not responding properly.", delegate: nil, cancelButtonTitle: "Try Again")
alertView.alertViewStyle = .default
alertView.show()
}
break
}
}
}
// Chat Message[ User Message Page for Perticular Listing (next step of above api) ]
func chatMessageShow(){
let prs = [
"user_id":Current_User.ID,
"receiver_id":receivedId,
"deal_id":listId,
"user_listing_msg": "1" as String
]
Service.StartWithoutLoading(prs as [String : AnyObject]?, onCompletion: { result in
guard let resultDict = result["result"] as? [String:AnyObject] else{return}
let user_image = resultDict["user_image"] as? String
UserDefaults.standard.set(user_image, forKey: "user_image")
let shopkeeper_name = resultDict["shopkeeper_name"] as? String
UserDefaults.standard.set(shopkeeper_name, forKey: "shopkeeper_name")
guard let messageArray = resultDict["message"] as? [[String:AnyObject]] else{return}
print("Message Array : \(messageArray)")
DispatchQueue.main.async { () -> Void in
for message in messageArray{
guard let msg = message["message"] as? String else{ return }
let is_self = message["is_self"] as? String
let messageID = message["id"] as? String
let added_time = message["added_time"]
guard let timeinterval : TimeInterval = (added_time)?.doubleValue else{return}
let dateFromServer = NSDate(timeIntervalSince1970:timeinterval)
let dateFormater : DateFormatter = DateFormatter()
dateFormater.dateFormat = "dd-MMM-yyyy hh:mm a" // 22-Sep-2017 02:53 PM
let is_attachment = message["is_attachment"] as? String
let photo = JSQPhotoMediaItem()
if is_self == "1"{
if is_attachment == "0"{
let message = MyMessage(senderId: is_self!, senderDisplayName: shopkeeper_name!, date: dateFromServer as Date, text: msg, messageID: messageID!)
self.messages.append(message)
self.finishReceivingMessage(animated: true)
}
else if is_attachment == "1"{
if let url = NSURL(string:msg ){
guard let data = NSData(contentsOf: url as URL) else{ return }
let image = UIImage(data: data as Data)
photo.image = image
photo.appliesMediaViewMaskAsOutgoing = true
let message = MyMessage(senderId: is_self!, senderDisplayName: shopkeeper_name!, date: dateFromServer as Date!, media: photo, messageID: messageID!)
self.messages.append(message)
print(message.messageID)
self.finishReceivingMessage(animated: true)
}
}
}
else{
if is_attachment == "0"{
let message = MyMessage(senderId: "0", senderDisplayName: user_image!, date: dateFromServer as Date!, text: msg, messageID: messageID!)
print(message.messageID)
self.messages.append(message)
self.finishReceivingMessage(animated: true)
}
else if is_attachment == "1"{
if let url = NSURL(string:msg ){
guard let data = NSData(contentsOf: url as URL) else{ return }
let image = UIImage(data: data as Data)
photo.image = image
photo.appliesMediaViewMaskAsOutgoing = false
let message = MyMessage(senderId: "0", senderDisplayName: user_image!, date: dateFromServer as Date!, media: photo, messageID: messageID!)
print(message.messageID)
self.messages.append(message)
self.finishReceivingMessage(animated: true)
}
}
}
}
self.collectionView.reloadData()
self.collectionView.layoutIfNeeded()
}
})
}
// Chat Message End
}
public extension Date {
public func dateString (format: String = "dd MMM, yyyy") -> String {
let formatter = DateFormatter()
formatter.dateFormat = format
return formatter.string(from: self)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment