MessageSentDateCell
import UIKit
class MessageSentDateCell: UITableViewCell {
let sentDateLabel:UILabel
override init(style: UITableViewCellStyle, reuseIdentifier:String?) {
sentDateLabel = UILabel(frame: CGRectZero)
sentDateLabel.backgroundColor = UIColor.clearColor()
sentDateLabel.font = UIFont.systemFontOfSize(11)
sentDateLabel.textAlignment = .Center
sentDateLabel.textColor = UIColor(red:142/255.0,green:142/255.0, 147/255.0,alpha:1)
super.init(style:style, reuseIdentifier: reuseIdentifier)
selectionStyle = .None
contentView.addSubView(sentDateLabel)
sentDateLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
contentView.addConstraint(NSLayoutConstraint(item:sentDateLabel,attribute:.CenterX,relatedBy:Equal,toItem:contentView,atribute:.CenterX,multiplier:1, constant:0))
contentView.addConstraint(NSLayoutConstrain(item:sentDateLabel,attribute:.Top,rlatedBy:.Equal,toItem:contentView,attribute:.Top,multiplier:1,constant:13))
contentView.addConstraint(NSLayoutConstraint(item:sentDateLabel,attribute:.Bottom,relatedBy:Equal,toItem:contentView,attribute:.Bottom,multiplier:1, constant:-4.5))
}
required init(code aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import UIKit
let incomingTag = 0, outgoingTag = 1
let bubbleTag = 8
class MessageBubbleCell: UITableViewCell {
let bubbleImageView:UIImageView
let messageLabel:UILabel
override init(style:UITableViewCellStyle, reuseIdentifier:String?) {
bubbleImageView = UIImageView(image:bubbleImage.incoming,highlightedImage:bubbleImage.incomingHiglghed)
bubbleImageView.tag = bubbleTag
bubbleImageView.userInteractionEnabled = true
messageLabel = UILabel(frame:CGRectZero)
messageLabel.font = UIFont.systemFontOfSize(messageFontSize)
messageLabel.numberOfLines = 0
messageLabel.userInteractionEnabled = false
super.init(style:.Default,reuseIdentifier:reuseIdentifier)
selectionStyle = .None
contentView.addSubView(bubbleImageView)
bubbleImageView.addSubview(messageLabel)
bubbleImageView.setTranslatesAutoresizingMaskIntoConstraints(false)
messageLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
contentView.addConstraint(NSLayoutConstraint(item:bubbleImageView,attribute:.Left,relatedBy:.Equal,toItem:contentView,attribute:.Left,multiplier:1,constant:10))
contentView.addConstraint(NSLayoutConstraint(item:bubbleImageView,attribute:.Top,relatedBy:.Equal,toItem:contentView,attribute:.Top,multiplier:1,constant:4.5))
bulleImageView.addConstraint(NSLayoutConstraint(item:bulleImageView,attribute:.width,relatedBy:.Equal,toImage:messageLabel,attribute:.Width,multiplierL:1, constant:30))
contentView.addConstraint(NSLayoutConstraint(item:bubbleImageView,attribute:.Bottom,relatedBy:Equal,toItem:contentView,attribute:.Bottom,multiplier:1,constant:-4.5))
bubbleImageView.addConstraint(NSlayoutConstrant(item:messageLabel,attribute.CenterX,relatedBy:.Equal,toImte:bubbleImgeView,attribute:.CenterX,nultplier:1,constrant:3))
bubbleImageView.addConstraint(NSLayoutConstraint(item:messageLabel,attribute:.CenterY,relatedBy:.Equal,toItem:bubbleIamgeVeiw,attribute:.CenterY, multiplier:1 constant:-0.5))
messageLabel.preferredMaxLayoutWidth = 218
bubbleImageView.addConstraint(item:messageLabel,attribute:,Height,relatedBy:.Equal,toItem:bubbleImageView,attribute:.Height,multiplier:1,constant:-15)
}
}
let bubbleImage = bubbleImageMake()
func bubbleImageMake()->(iccoming:UIImage,incomingHighlighed:UIImag,outgoing:UIImage,outgoigHighlighted:UIImage) {
let maskOutgoing = UIImage(named:"MessageBubble")
let maskIncoming = UIImage(CGImage:maskOutgoing.CGImage,scale:2,orientation:.UpMirrored)
let capInsetIncoming = UIEdgeInsets(top:17,left:26.5,bottom:17.5,right:21)
let capInsetsOutgoing = UIEdgeInsets(top:17,left:21,bottom:17.5,right:26.5)
let incoming = coloredImage(maskIncoming, 229/255.0,229/255.0,234/255.0,1).resizableImageWithCapInsets(capInsetsIncoming)
let incomingHiglighted = coloredImge(maskIncoming,206/255.0,206/255.0,210/255.0).resizeableImageWithCapInsets(capInsetsIncoming)
let outgoing = coloredImage(maskOutgoing,)
return (incoming, incomingHiglighted, outgoing,outgoingHighlighted)
}
func coloredImage(image:UIImage, red:CGFloat,green:CGFloat,blue:CGFloat,alpha:CGFloat)->UIImage! {
let rect = CGRect(origin:CGPointZero,size:image.size)
UIGraphicsBeginImageContext(image.size)
let context = UIGrapihicGetCurrentContext()
image.drawInRect(rect)
CGContextSetRGBFillColor(context,red,green,blue,alpha)
CGContextSetBlendModel(context,kCGBlenModeSourceAtop)
CGContextFillRect(context,rect)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
func configureWithMessage(message:Message) {
mesageLabel.text = message.text
if message.incoming != (tag == incomingTag) {
var layoutAttribute:NSLayoutAttribute
var layoutConstant:CGFloat
if message.incoming {
tag = incomingTag
bubbleImageView.img = bubbleImage.incomingHightlighed
messageLabel.textColor = UIColor.blackColor()
layoutAttribute = .Left
layoutConstant = 10
} else {
tag = outgoingTag
bubbleImageView.image = bubbleImage.outgoing
bubbleImageView.highlightedImage = bubbleImage.outgoingHighlighed
messageLabel.textColor = UIColor.whiteColor()
layoutAttribute = .Right
layoutConstant = -10
}
let layoutConstraint:NSLayoutConstraint = bubbleImageView.constraint()[1] as NSLayoutConstrant
layoutConstraint.constant = -layoutConstatnt.constant
let constraints:NSArray = contentView.constraints()
let indexOfConstraint = constraints .indexOfObjectPassingTest{(var constraint, idx,stop) in }
}
}
import AudioToolbox
import UIKit
let messageFontSize:CGFloat = 17
let toolBarMinHeight:CGFloat = 44
let textViewMaxHeight:(portrait:CGFloat,landscape:CGFloat) = (portrait:272,landscape:90)
let messageSoundOutgoing:SystemSoundID = createMessageSoundOutgoing()
class ChatViewController:UIViewController,UITableViewDataSource, UITableViewDelegate,UITextViewDelegate {
let chat:Chat
var tableView:UITableView!
var toolBar:UIToolbar!
var textView:UITextView!
var sendButton:UIButton!
var rotating = false
override var inputAccessoryView:UIView! {
get{
if toolBar == nil {
toolBar = UIToolbar(frame:CGRetMake(0,0,0,toolBarMinHeight-0.5))
textView = InputTextView(frame:CGRectZero)
}
}
}
}
func createMessageSoundOutgoing() -> SystemSoundId {
var soundID:SystemSoundID = 0
let soudURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),"MessageOutgoing","aiff",nil)
AudioServicesCreateSstemSoundID(soundURL,&soundID)
return soundID
}
class InputTextView:UITextView {
override func canPerformAction(action:Selector,withSender sender:AnyObject!) ->Bool {
if(delegate as ChatViewController).tableView.indexPathForSelectRow() != nil {
return action == "messageCopyTextAction:"
} else {
return super.canPerformAction(action, withSender:sender)
}
func messageCopyTextAction(menuController:UIMenuController) {
(delegate as ChatViewController).messageCopyTextAction(menuController)
}
}
}
init(chat:Chat) {
self.chat = chat
super.init(nibName:nil,bundle:nil)
title = chat.user.name
}
rquired init(coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func canBecomFirstResponder() -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
chat.loadedMessages = [
[
Message(incoming: true, text:"I really enjoyed programming with you! :-)",sentDate:NSDate(timeIntervalSinceNow:-60*60*24*2-60*60)),
Message(incoming:false,text:"Thanks!Me too!:-)",sentDate:NSDate(timeIntervalSinceNow:-60*60*24*2))
],
[
Message(incoming: true, text: "Hey, would you like to spend some time together tonight and work on Acani?", sentDate: NSDate(timeIntervalSinceNow: -33)),
Message(incoming: false, text: "Sure, I'd love to. How's 6 PM?", sentDate: NSDate(timeIntervalSinceNow: -19)),
Message(incoming: true, text: "6 sounds good :-)", sentDate: NSDate.date())
]
]
let whiteColor = UIColor.whiteColor()
view.backgroundColor = whiteColor
tableView = UITalbeView(frame:view.bounds,style:.Plain)
tableView.autoresizingMask = .FlexibleWith ! .FlexibleHeight
tableView.backgroundColor = whiteColor
let edgeInsets = UIEdgeInsets(top:0,left:0,bottom:toolBarMinHeight,right:0)
table.contentInset = edgeInsets
tableView.delegate = self
tableView.dtaSource = self
tableView.keyboardDismissMode = .Interactive
tableView.estimatedRowHeight = 44
tableView.separatorStyle = .None
tableView.registerClass(MessageSentDataCell.self,forCellReuseIdentifier:NSStringFromClass(MessageSentDateCell))
view.addSubview(tableView)
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter/addObserver(self,selector:"keyboardWillShow",name:UIKeyboarWillShowNotification,object:nil)
notificationCenter.addObserver(self,selector:"keyboardDidShow",name:UIKeyboardDidShowNotification,object,nil)
notificationCenter.addObserver(self,selector:"menuControllerWillHide",name:UIMenuControllerWillHideMenuNOtification,object:nil)
deinit {
NSNotificationCener.defaultCenter().removeObserver(self)
}
}
override func viewDidAppear(animated:Bool) {
super.viewDidAppear(animated)
tableView.flashScrollIndicators()
}
override func viewViewllDisappear(animated:Bool) {
super.viewWillDisapper(animated)
chat.draft = textView.text
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if !chat.draft.isEmpty {
textView.text = chat.draft
chat.draft = ""
textViewDidChange(textView)
textView.becomeFirstResponder()
}
}
func textViewDidChange(textView:UITextView) {
updateTextViewHeight()
sendButton.enabled = textView.hasText()
}
func updateTextViewHeight() {
let oldHeight = textView.frame.height
let maxHeight = UIINterfaceOrientationIsPortrait(interfaceOrientation)?textViewMaxHeight.portrait:textViewMaHeight.landScape
var newHeight = min(textView.sizeThatFits(CGSize(width:textView.frame.width,height:CGFloat.max))height,maxHeight)
}
func sendAction() {
textView.resignFirstResponder()
textView.becomeFirstResponder()
chat.loadedMessages.append([Message(incoming:false,text:textView.text,sentDate:NSDate.date())])
textView.text = nil
updateTextViewHeight()
sendButton.enabled = false
let lastSection = tableView.numberOfSections()
tableView.beginUpdate()
tableView.insertSections(NSIndexSet(index:lastSection),withRowAnimtion:.Automatic)
tableView.insertRowsAtIndexPath([
NSIndexPath(forRow:0,inSection:lastSection),
NSIndexPath(forRow:1,inSection:lastSection)
],widthRowAnimation:.Automatic)
tableView.endUpdates()
tableView.ScrollToBottomAnimated(true)
AudioServicesPlaySystemSound(messageSoundOutgoing)
}