Skip to content

Commit

Permalink
Enhancement: Create a Cocoapod spec, allowing for easy usage in other…
Browse files Browse the repository at this point in the history
… projects, as well as dependencies to other projects

Enhancement:  Dependency on IODProfanityFilter, Allow for profanity filtering
  • Loading branch information
Kevin Lohman committed Jul 26, 2016
1 parent 12226d3 commit 0aa36f2
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 32 deletions.
136 changes: 136 additions & 0 deletions LGSimpleChat.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#
# Be sure to run `pod spec lint SimpleChat.podspec' to ensure this is a
# valid spec and to remove all comments including this before submitting the spec.
#
# To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
#

Pod::Spec.new do |s|

# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# These will help people to find your library, and whilst it
# can feel like a chore to fill in it's definitely to your advantage. The
# summary should be tweet-length, and the description more in depth.
#

s.name = "LGSimpleChat"
s.version = "2.0.0"
s.summary = "An easy to use bubble chat UI as an alternative to the traditional iOS talk bubbles."

# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
An easy to use bubble chat UI as an alternative to the traditional iOS talk bubbles.
DESC

s.homepage = "https://github.com/LoganWright/SimpleChat"
# s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"


# ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Licensing your code is important. See http://choosealicense.com for more info.
# CocoaPods will detect a license file if there is a named LICENSE*
# Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
#

s.license = { :type => "MPL 2.0", :file => "License.txt" }


# ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Specify the authors of the library, with email addresses. Email addresses
# of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
# accepts just a name if you'd rather not provide an email address.
#
# Specify a social_media_url where others can refer to, for example a twitter
# profile URL.
#

s.author = "Logan Wright"

# ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# If this Pod runs only on iOS or OS X, then specify the platform and
# the deployment target. You can optionally include the target after the platform.
#

# s.platform = :ios
s.platform = :ios, "6.0"

# When using multiple platforms
# s.ios.deployment_target = "5.0"
# s.osx.deployment_target = "10.7"
# s.watchos.deployment_target = "2.0"
# s.tvos.deployment_target = "9.0"


# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Specify the location from where the source should be retrieved.
# Supports git, hg, bzr, svn and HTTP.
#


# LOGAN -- You'll have to update the link below to include the tag 2.0.0 that you create for version 2
s.source = { :git => "https://github.com/LoganWright/SimpleChat.git" }


# ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# CocoaPods is smart about how it includes source code. For source files
# giving a folder will include any swift, h, m, mm, c & cpp files.
# For header files it will include any header in the folder.
# Not including the public_header_files will make all headers public.
#

s.source_files = "SimpleChat/LGSimpleChat/LGSimpleChat.swift"
# s.exclude_files = "Classes/Exclude"

# s.public_header_files = "Classes/**/*.h"


# ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# A list of resources included with the Pod. These are copied into the
# target bundle with a build phase script. Anything else will be cleaned.
# You can preserve files from being cleaned, please don't preserve
# non-essential files like tests, examples and documentation.
#

# s.resource = "icon.png"
# s.resources = "Resources/*.png"

# s.preserve_paths = "FilesToSave", "MoreFilesToSave"


# ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# Link your library with frameworks, or libraries. Libraries do not include
# the lib prefix of their name.
#

s.framework = "UIKit"
# s.frameworks = "SomeFramework", "AnotherFramework"

# s.library = "iconv"
# s.libraries = "iconv", "xml2"


# ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
#
# If your library depends on compiler flags you can set them in the xcconfig hash
# where they will only apply to your library. If you depend on other Podspecs
# you can include multiple dependencies to ensure it works.

# s.requires_arc = true

# s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
s.dependency "IODProfanityFilter", "~> 1.0.0"

end
76 changes: 44 additions & 32 deletions SimpleChat/LGSimpleChat/LGSimpleChat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ https://tldrlegal.com/license/mozilla-public-license-2.0-(mpl-2)

import UIKit
import Foundation
import IODProfanityFilter

// MARK: Message

class LGChatMessage : NSObject {
public class LGChatMessage : NSObject {

enum SentBy : String {
public enum SentBy : String {
case User = "LGChatMessageSentByUser"
case Opponent = "LGChatMessageSentByOpponent"
}

// Useful to provide meta data for filtering predicate
var userInfo = [ String : AnyObject ]()
public var userInfo = [ String : AnyObject ]()

// MARK: ObjC Compatibility

Expand All @@ -35,10 +36,10 @@ class LGChatMessage : NSObject {


// Custom color for the speech bubble, if nil, will use default
var color : UIColor?
public var color : UIColor?

// Set to any string to have a custom Gravatar used as the icon, same string will always have the same icon.
var gravatarString : String?
public var gravatarString : String?

class func SentByUserString() -> String {
return LGChatMessage.SentBy.User.rawValue
Expand All @@ -63,11 +64,11 @@ class LGChatMessage : NSObject {

// MARK: Public Properties

var sentBy: SentBy
var content: String
var timeStamp: NSTimeInterval?
public var sentBy: SentBy
public var content: String
public var timeStamp: NSTimeInterval?

required init (content: String, sentBy: SentBy, timeStamp: NSTimeInterval? = nil){
required public init (content: String, sentBy: SentBy, timeStamp: NSTimeInterval? = nil){
self.sentBy = sentBy
self.timeStamp = timeStamp
self.content = content
Expand All @@ -91,13 +92,13 @@ class LGChatMessage : NSObject {
}
}

override var hashValue: Int {
override public var hashValue: Int {
get {
return Int.addWithOverflow(Int.addWithOverflow(sentBy.hashValue, (timeStamp ?? 0).hashValue).0, content.hashValue).0
}
}

override func isEqual(object: AnyObject?) -> Bool {
override public func isEqual(object: AnyObject?) -> Bool {
guard let object = object as? LGChatMessage else {
return false
}
Expand All @@ -107,10 +108,12 @@ class LGChatMessage : NSObject {

// MARK: Message Cell

class LGChatMessageCell : UITableViewCell {
public class LGChatMessageCell : UITableViewCell {

var gravatarString : String?

var profanityFilter : String?

// MARK: Global MessageCell Appearance Modifier

struct Appearance {
Expand Down Expand Up @@ -203,7 +206,11 @@ class LGChatMessageCell : UITableViewCell {
Use this in cellForRowAtIndexPath to setup the cell.
*/
func setupWithMessage(message: LGChatMessage) -> CGSize {
textView.text = message.content
var content = message.content
if let profanityFilter = profanityFilter {
content = IODProfanityFilter.stringByFilteringString(content, withReplacementString: profanityFilter)
}
textView.text = content
size = textView.sizeThatFits(maxSize)
if size.height < minimumHeight {
size.height = minimumHeight
Expand Down Expand Up @@ -244,27 +251,31 @@ class LGChatMessageCell : UITableViewCell {

// MARK: Chat Controller

@objc protocol LGChatControllerDelegate {
@objc public protocol LGChatControllerDelegate {
optional func shouldChatController(chatController: LGChatController, addMessage message: LGChatMessage) -> Bool
optional func chatController(chatController: LGChatController, didAddNewMessage message: LGChatMessage)
}

class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataSource, LGChatInputDelegate {
public class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataSource, LGChatInputDelegate {
var gravatarCache = [ String : UIImage ]()
var pendingGravatarLoad = [ String ]()

// Set this to to a replacement string ex. "********" to filter profanity
public var profanityFilter : String? {
didSet {
tableView.reloadData()
}
}

// Set this value to filter messages
var filter : NSPredicate? {
public var filter : NSPredicate? {
didSet {
tableView.reloadData()
}
}

typealias isOrderedBefore = (LGChatMessage, LGChatMessage) -> Bool

// Set this value to apply sorting
var sort : isOrderedBefore? {
public var sort : ((LGChatMessage, LGChatMessage) -> Bool)? {
didSet {
if let sort = sort {
messages.sortInPlace(sort)
Expand All @@ -274,7 +285,7 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS
}

// Set to true to perform duplicate checking
var checkForDuplicates = false
public var checkForDuplicates = false

// MARK: Constants

Expand All @@ -290,7 +301,7 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS
*/
var messages: [LGChatMessage] = []
var opponentImage: UIImage?
weak var delegate: LGChatControllerDelegate?
public weak var delegate: LGChatControllerDelegate?

// MARK: Private Properties

Expand All @@ -302,22 +313,22 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS

// MARK: Life Cycle

override func viewDidLoad() {
override public func viewDidLoad() {
super.viewDidLoad()
self.setup()
}

override func viewWillAppear(animated: Bool) {
override public func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.listenForKeyboardChanges()
}

override func viewDidAppear(animated: Bool) {
override public func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.scrollToBottom()
}

override func viewWillDisappear(animated: Bool) {
override public func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.unregisterKeyboardObservers()
}
Expand Down Expand Up @@ -414,7 +425,7 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS
}

// MARK: Rotation
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
override public func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition({ (_) in
self.tableView.reloadData()
}) { (_) in
Expand All @@ -440,7 +451,7 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS

// MARK: New messages

func addNewMessage(message: LGChatMessage) {
public func addNewMessage(message: LGChatMessage) {
if checkForDuplicates {
if messages.contains(message) {
return // Dupe
Expand Down Expand Up @@ -479,7 +490,7 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS

// MARK: UITableViewDelegate

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let message = messages[indexPath.row]

if let filter = filter {
Expand All @@ -494,23 +505,23 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS
return height
}

func scrollViewDidScroll(scrollView: UIScrollView) {
public func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.dragging {
self.chatInput.textView.resignFirstResponder()
}
}

// MARK: UITableViewDataSource

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
public func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.messages.count;
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("identifier", forIndexPath: indexPath) as! LGChatMessageCell
let message = self.messages[indexPath.row]
cell.hidden = false
Expand All @@ -519,6 +530,7 @@ class LGChatController : UIViewController, UITableViewDelegate, UITableViewDataS
cell.hidden = true
}
}
cell.profanityFilter = profanityFilter
cell.gravatarString = message.gravatarString
cell.opponentImageView.image = message.sentBy == .Opponent ? self.opponentImage : nil
if let gravatarString = cell.gravatarString {
Expand Down

0 comments on commit 0aa36f2

Please sign in to comment.