Compare commits

...

33 Commits

Author SHA1 Message Date
Peter Zignego a33b2d08de Remove non-error logging 2016-01-02 18:39:26 -05:00
Peter Zignego bb7271c7b3 Merge pull request #3 from pvzig/features/callbacks
v0.9.5
2016-01-02 18:33:19 -05:00
Peter Zignego 3d9711ab32 Update readme with delegate methods 2016-01-02 18:31:16 -05:00
Peter Zignego a424760f34 Delegate uniformity tweaks 2016-01-02 18:20:56 -05:00
Peter Zignego a452bd2526 Update podspec 2016-01-02 18:13:28 -05:00
Peter Zignego f4e28af783 Update Starscream version 2016-01-02 18:10:34 -05:00
Peter Zignego 95f39c4f5d Remove client helper func 2016-01-02 18:10:11 -05:00
Peter Zignego f000e8152e Update copyright to 2016 2016-01-02 18:10:00 -05:00
Peter Zignego 62f203ba20 Add support for stars and reactions for files and file comments 2016-01-02 18:01:09 -05:00
Peter Zignego 3c48d19b86 Fix if init check 2016-01-02 18:00:07 -05:00
Peter Zignego ffb05ca19f Remove lazy (crashes) 2016-01-02 17:59:36 -05:00
Peter Zignego ac8780dfc2 If client is unware of a file, add it for relevant events 2016-01-02 14:06:35 -05:00
Peter Zignego 9bc4da8d77 Allow starring of files 2016-01-02 14:05:56 -05:00
Peter Zignego 0f9fc0c98d Add client disconnected callback 2016-01-02 14:04:56 -05:00
Peter Zignego 4ddee594ab Channel property fixes 2016-01-01 19:17:07 -05:00
Peter Zignego 02179975ec Support mpims 2016-01-01 19:16:44 -05:00
Peter Zignego dccc9f86bd Correct group channel implementation 2016-01-01 19:16:08 -05:00
Peter Zignego c41126923d Correct additional property types 2016-01-01 19:15:39 -05:00
Peter Zignego 36b746f8a6 Smarter handling for optional values 2016-01-01 13:04:04 -05:00
Peter Zignego 794cf83d7c Remove unnecessary breaks 2015-12-30 23:39:34 -05:00
Peter Zignego ea1e947e1a Update properties to correct types 2015-12-30 23:39:11 -05:00
Peter Zignego f1cd8e9961 Add support dnd_updated and dnd_updated_user events 2015-12-30 23:38:01 -05:00
Peter Zignego 73bbde9486 Don't crash on unknown event types 2015-12-30 20:05:30 -05:00
Peter Zignego f73b1a44d5 Add support for subteams 2015-12-26 21:24:29 -05:00
Peter Zignego 5ce0a2d32a Update for change to Client.channels optionality 2015-12-26 13:43:53 -05:00
Peter Zignego 51c9fe61fd Replace C-style loops 2015-12-26 13:42:17 -05:00
Peter Zignego 71ff3da8f9 Prefer Dictionary and Array shorthand 2015-12-26 13:40:52 -05:00
Peter Zignego f81d4bc7b9 Remove deprecated property timestamp 2015-12-26 13:37:05 -05:00
Peter Zignego 7d7a31a243 Replace DM with IM to reflect the API 2015-12-26 13:35:22 -05:00
Peter Zignego 200ba1fe2a Access control improvements 2015-12-26 13:28:26 -05:00
Peter Zignego fab220aae5 Fix file handling - WIP 2015-12-21 11:21:39 -05:00
Peter Zignego 1c36bae33a Add delegate callbacks - WIP 2015-12-21 11:21:23 -05:00
Peter Zignego d5c03d34b2 Fix preference change crashes 2015-12-21 11:20:38 -05:00
19 changed files with 1132 additions and 511 deletions
+3 -3
View File
@@ -1,10 +1,10 @@
PODS:
- Starscream (1.0.0)
- Starscream (1.0.2)
DEPENDENCIES:
- Starscream
SPEC CHECKSUMS:
Starscream: 24012f5dc21c634b66e2270b1bb95771b5316d5b
Starscream: 40e2c4c1c770d811f24116b8b7dbeb4542c56767
COCOAPODS: 0.38.2
COCOAPODS: 0.39.0
+91
View File
@@ -32,6 +32,97 @@ Client.sharedInstance.connect()
```
Once connected, the client will begin to consume any messages sent by the Slack RTM API.
####Delegate methods
There are a number of delegates that you can set to receive callbacks for certain events.
#####SlackEventsDelegate
```swift
func clientConnected()
func clientDisconnected()
func preferenceChanged(preference: String, value: AnyObject)
func userChanged(user: User)
func presenceChanged(user: User?, presence: String?)
func manualPresenceChanged(user: User?, presence: String?)
func botEvent(bot: Bot)
```
#####MessageEventsDelegate
```swift
func messageSent(message: Message)
func messageReceived(message: Message)
func messageChanged(message: Message)
func messageDeleted(message: Message?)
```
#####ChannelEventsDelegate
```swift
func userTyping(channel: Channel?, user: User?)
func channelMarked(channel: Channel, timestamp: String?)
func channelCreated(channel: Channel)
func channelDeleted(channel: Channel)
func channelRenamed(channel: Channel)
func channelArchived(channel: Channel)
func channelHistoryChanged(channel: Channel)
func channelJoined(channel: Channel)
func channelLeft(channel: Channel)
```
#####DoNotDisturbEventsDelegate
```swift
doNotDisturbUpdated(dndStatus: DoNotDisturbStatus)
doNotDisturbUserUpdated(dndStatus: DoNotDisturbStatus, user: User?)
```
#####GroupEventsDelegate
```swift
func groupOpened(group: Channel)
```
#####FileEventsDelegate
```swift
func fileProcessed(file: File)
func fileMadePrivate(file: File)
func fileDeleted(file: File)
func fileCommentAdded(file: File, comment: Comment)
func fileCommentEdited(file: File, comment: Comment)
func fileCommentDeleted(file: File, comment: Comment)
```
#####PinEventsDelegate
```swift
func itemPinned(item: Item?, channel: Channel?)
func itemUnpinned(item: Item?, channel: Channel?)
```
#####StarEventsDelegate
```swift
func itemStarred(item: Item, star: Bool)
```
#####ReactionEventsDelegate
```swift
func reactionAdded(reaction: String?, item: Item?)
func reactionRemoved(reaction: String?, item: Item?)
```
#####TeamEventsDelegate
```swift
func teamJoined(user: User)
func teamPlanChanged(plan: String)
func teamPreferencesChanged(preference: String, value: AnyObject)
func teamNameChanged(name: String)
func teamDomainChanged(domain: String)
func teamEmailDomainChanged(domain: String)
func teamEmojiChanged()
```
#####SubteamEventsDelegate
```swift
func subteamEvent(userGroup: UserGroup)
func subteamSelfAdded(subteamID: String)
func subteamSelfRemoved(subteamID: String)
```
###Examples
####Sending a Message:
```swift
+2 -2
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SlackKit"
s.version = "0.9.0"
s.version = "0.9.5"
s.summary = "a Slack client library for iOS and OS X written in Swift"
s.homepage = "https://github.com/pvzig/SlackKit"
s.license = 'MIT'
@@ -12,5 +12,5 @@ Pod::Spec.new do |s|
s.requires_arc = true
s.source_files = 'SlackKit/*.swift'
s.frameworks = 'Foundation'
s.dependency 'Starscream', '~> 1.0.1'
s.dependency 'Starscream', '~> 1.0.2'
end
+20 -12
View File
@@ -7,18 +7,20 @@
objects = {
/* Begin PBXBuildFile section */
2661A68F1BBF60E60026F67B /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6821BBF60E60026F67B /* Bot.swift */; settings = {ASSET_TAGS = (); }; };
2661A6901BBF60E60026F67B /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6831BBF60E60026F67B /* Channel.swift */; settings = {ASSET_TAGS = (); }; };
2661A6911BBF60E60026F67B /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6841BBF60E60026F67B /* Client.swift */; settings = {ASSET_TAGS = (); }; };
2661A6921BBF60E60026F67B /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6851BBF60E60026F67B /* Event.swift */; settings = {ASSET_TAGS = (); }; };
2661A6931BBF60E60026F67B /* EventDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6861BBF60E60026F67B /* EventDispatcher.swift */; settings = {ASSET_TAGS = (); }; };
2661A6941BBF60E60026F67B /* EventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6871BBF60E60026F67B /* EventHandler.swift */; settings = {ASSET_TAGS = (); }; };
2661A6951BBF60E60026F67B /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6881BBF60E60026F67B /* File.swift */; settings = {ASSET_TAGS = (); }; };
2661A6971BBF60E60026F67B /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68A1BBF60E60026F67B /* Message.swift */; settings = {ASSET_TAGS = (); }; };
2661A6991BBF60E60026F67B /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68C1BBF60E60026F67B /* Team.swift */; settings = {ASSET_TAGS = (); }; };
2661A69A1BBF60E60026F67B /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68D1BBF60E60026F67B /* Types.swift */; settings = {ASSET_TAGS = (); }; };
2661A69B1BBF60E60026F67B /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68E1BBF60E60026F67B /* User.swift */; settings = {ASSET_TAGS = (); }; };
FFE3AC870D1C42EF276CCA2D /* Pods_SlackKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 407A2ABFC0611867E2BE34D0 /* Pods_SlackKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
2661A68F1BBF60E60026F67B /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6821BBF60E60026F67B /* Bot.swift */; };
2661A6901BBF60E60026F67B /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6831BBF60E60026F67B /* Channel.swift */; };
2661A6911BBF60E60026F67B /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6841BBF60E60026F67B /* Client.swift */; };
2661A6921BBF60E60026F67B /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6851BBF60E60026F67B /* Event.swift */; };
2661A6931BBF60E60026F67B /* EventDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6861BBF60E60026F67B /* EventDispatcher.swift */; };
2661A6941BBF60E60026F67B /* EventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6871BBF60E60026F67B /* EventHandler.swift */; };
2661A6951BBF60E60026F67B /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A6881BBF60E60026F67B /* File.swift */; };
2661A6971BBF60E60026F67B /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68A1BBF60E60026F67B /* Message.swift */; };
2661A6991BBF60E60026F67B /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68C1BBF60E60026F67B /* Team.swift */; };
2661A69A1BBF60E60026F67B /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68D1BBF60E60026F67B /* Types.swift */; };
2661A69B1BBF60E60026F67B /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2661A68E1BBF60E60026F67B /* User.swift */; };
26EB95961C285CEE00BD1F13 /* EventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EB95951C285CEE00BD1F13 /* EventDelegate.swift */; };
26EB959D1C2F10CA00BD1F13 /* UserGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26EB959C1C2F10CA00BD1F13 /* UserGroup.swift */; };
FFE3AC870D1C42EF276CCA2D /* Pods_SlackKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 407A2ABFC0611867E2BE34D0 /* Pods_SlackKit.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -36,6 +38,8 @@
2661A68E1BBF60E60026F67B /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
2661A6A41BBF62FF0026F67B /* SlackKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SlackKit.h; sourceTree = "<group>"; };
266E05F01BBF780C00840D76 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
26EB95951C285CEE00BD1F13 /* EventDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventDelegate.swift; sourceTree = "<group>"; };
26EB959C1C2F10CA00BD1F13 /* UserGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserGroup.swift; sourceTree = "<group>"; };
407A2ABFC0611867E2BE34D0 /* Pods_SlackKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SlackKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4347F92F3932C96C23B10B2A /* Pods-SlackKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SlackKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-SlackKit/Pods-SlackKit.release.xcconfig"; sourceTree = "<group>"; };
F59B6A12F1C4C4E24C58E1BF /* Pods-SlackKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SlackKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SlackKit/Pods-SlackKit.debug.xcconfig"; sourceTree = "<group>"; };
@@ -89,11 +93,13 @@
2661A6851BBF60E60026F67B /* Event.swift */,
2661A6861BBF60E60026F67B /* EventDispatcher.swift */,
2661A6871BBF60E60026F67B /* EventHandler.swift */,
26EB95951C285CEE00BD1F13 /* EventDelegate.swift */,
2661A6881BBF60E60026F67B /* File.swift */,
2661A68A1BBF60E60026F67B /* Message.swift */,
2661A68C1BBF60E60026F67B /* Team.swift */,
2661A68D1BBF60E60026F67B /* Types.swift */,
2661A68E1BBF60E60026F67B /* User.swift */,
26EB959C1C2F10CA00BD1F13 /* UserGroup.swift */,
2661A6A41BBF62FF0026F67B /* SlackKit.h */,
266E05F01BBF780C00840D76 /* Info.plist */,
);
@@ -232,6 +238,8 @@
2661A6911BBF60E60026F67B /* Client.swift in Sources */,
2661A6941BBF60E60026F67B /* EventHandler.swift in Sources */,
2661A68F1BBF60E60026F67B /* Bot.swift in Sources */,
26EB959D1C2F10CA00BD1F13 /* UserGroup.swift in Sources */,
26EB95961C285CEE00BD1F13 /* EventDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+5 -5
View File
@@ -1,7 +1,7 @@
//
// Bot.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,14 +23,14 @@
public struct Bot {
let id: String?
public let id: String?
internal(set) public var name: String?
internal(set) public var icons: Dictionary<String, AnyObject>?
internal(set) public var icons: [String: AnyObject]?
internal init?(bot:Dictionary<String, AnyObject>?) {
internal init?(bot: [String: AnyObject]?) {
id = bot?["id"] as? String
name = bot?["name"] as? String
icons = bot?["icons"] as? Dictionary<String, AnyObject>
icons = bot?["icons"] as? [String: AnyObject]
}
}
+18 -15
View File
@@ -1,7 +1,7 @@
//
// Channel.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -24,13 +24,14 @@
public struct Channel {
public let id: String?
public let created: String?
public let created: Int?
public let creator: String?
internal(set) public var name: String?
internal(set) public var isArchived: Bool?
internal(set) public var isGeneral: Bool?
public let isGroup: Bool?
public let isDM: Bool?
public let isIM: Bool?
public let isMPIM: Bool?
internal(set) public var user: String?
internal(set) public var isUserDeleted: Bool?
internal(set) public var isOpen: Bool?
@@ -42,29 +43,30 @@ public struct Channel {
internal(set) public var unread: Int?
internal(set) public var unreadCountDisplay: Int?
internal(set) public var hasPins: Bool?
internal(set) public lazy var members = [String]()
internal(set) public var members = [String]()
// Client use
internal(set) public lazy var pinnedItems = [Item]()
internal(set) public lazy var usersTyping = [String]()
internal(set) public lazy var messages = Dictionary<String, Message>()
internal(set) public var pinnedItems = [Item]()
internal(set) public var usersTyping = [String]()
internal(set) public var messages = [String: Message]()
internal init?(channel:Dictionary<String, AnyObject>?) {
internal init?(channel: [String: AnyObject]?) {
id = channel?["id"] as? String
name = channel?["name"] as? String
created = channel?["created"] as? String
created = channel?["created"] as? Int
creator = channel?["creator"] as? String
isArchived = channel?["is_archived"] as? Bool
isGeneral = channel?["is_general"] as? Bool
isGroup = channel?["is_group"] as? Bool
isDM = channel?["is_im"] as? Bool
isIM = channel?["is_im"] as? Bool
isMPIM = channel?["is_mpim"] as? Bool
isUserDeleted = channel?["is_user_deleted"] as? Bool
user = channel?["user"] as? String
isOpen = channel?["is_open"] as? Bool
topic = Topic(topic: channel?["topic"] as? Dictionary<String, AnyObject>)
purpose = Topic(topic: channel?["purpose"] as? Dictionary<String, AnyObject>)
topic = Topic(topic: channel?["topic"] as? [String: AnyObject])
purpose = Topic(topic: channel?["purpose"] as? [String: AnyObject])
isMember = channel?["is_member"] as? Bool
lastRead = channel?["last_read"] as? String
latest = Message(message: channel?["message"] as? Dictionary<String, AnyObject>)
latest = Message(message: channel?["latest"] as? [String: AnyObject])
unread = channel?["unread_count"] as? Int
unreadCountDisplay = channel?["unread_count_display"] as? Int
hasPins = channel?["has_pins"] as? Bool
@@ -72,7 +74,7 @@ public struct Channel {
if let members = channel?["members"] as? [String] {
self.members = members
}
}
internal init?(id:String?) {
@@ -80,6 +82,7 @@ public struct Channel {
created = nil
creator = nil
isGroup = false
isDM = false
isIM = false
isMPIM = false
}
}
+104 -68
View File
@@ -1,7 +1,7 @@
//
// Client.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -26,18 +26,31 @@ import Starscream
public class Client: WebSocketDelegate {
public var connected = false
public var authenticated = false
public var authenticatedUser: User?
public var team: Team?
internal(set) public var connected = false
internal(set) public var authenticated = false
internal(set) public var authenticatedUser: User?
internal(set) public var team: Team?
public var channels: [String: Channel]?
public var users: [String: User]?
public var bots: [String: Bot]?
public var files: [String: File]?
internal lazy var sentMessages = [String: Message]()
internal(set) public var channels = [String: Channel]()
internal(set) public var users = [String: User]()
internal(set) public var userGroups = [String: UserGroup]()
internal(set) public var bots = [String: Bot]()
internal(set) public var files = [String: File]()
internal(set) public var sentMessages = [String: Message]()
//MARK: - Delegates
public var slackEventsDelegate: SlackEventsDelegate?
public var messageEventsDelegate: MessageEventsDelegate?
public var doNotDisturbEventsDelegate: DoNotDisturbEventsDelegate?
public var channelEventsDelegate: ChannelEventsDelegate?
public var groupEventsDelegate: GroupEventsDelegate?
public var fileEventsDelegate: FileEventsDelegate?
public var pinEventsDelegate: PinEventsDelegate?
public var starEventsDelegate: StarEventsDelegate?
public var reactionEventsDelegate: ReactionEventsDelegate?
public var teamEventsDelegate: TeamEventsDelegate?
public var subteamEventsDelegate: SubteamEventsDelegate?
private var token = "SLACK_AUTH_TOKEN"
public func setAuthToken(token: String) {
self.token = token
@@ -60,7 +73,7 @@ public class Client: WebSocketDelegate {
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! Dictionary<String, AnyObject>
let result = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject]
if (result["ok"] as! Bool == true) {
self.initialSetup(result)
let socketURL = NSURL(string: result["url"] as! String)
@@ -85,7 +98,7 @@ public class Client: WebSocketDelegate {
}
private func formatMessageToSlackJsonString(message: (msg: String, channel: String)) -> NSData? {
let json: Dictionary<String, AnyObject> = [
let json: [String: AnyObject] = [
"id": NSDate().timeIntervalSince1970,
"type": "message",
"channel": message.channel,
@@ -101,7 +114,7 @@ public class Client: WebSocketDelegate {
}
}
private func addSentMessage(dictionary:Dictionary<String, AnyObject>) {
private func addSentMessage(dictionary: [String: AnyObject]) {
var message = dictionary
let ts = message["id"] as? NSNumber
message.removeValueForKey("id")
@@ -118,76 +131,101 @@ public class Client: WebSocketDelegate {
}
//MARK: - Client setup
private func initialSetup(json: Dictionary<String, AnyObject>) {
team = Team(team: json["team"] as? Dictionary<String, AnyObject>)
authenticatedUser = User(user: json["self"] as? Dictionary<String, AnyObject>)
private func initialSetup(json: [String: AnyObject]) {
team = Team(team: json["team"] as? [String: AnyObject])
authenticatedUser = User(user: json["self"] as? [String: AnyObject])
authenticatedUser?.doNotDisturbStatus = DoNotDisturbStatus(status: json["dnd"] as? [String: AnyObject])
enumerateUsers(json["users"] as? Array)
enumerateChannels(json["channels"] as? Array)
enumerateGroups(json["groups"] as? Array)
enumerateDMs(json["ims"] as? Array)
enumerateMPIMs(json["mpims"] as? Array)
enumerateIMs(json["ims"] as? Array)
enumerateBots(json["bots"] as? Array)
enumerateSubteams(json["subteams"] as? [String: AnyObject])
}
private func enumerateUsers(users: Array<AnyObject>?) {
self.users = [String: User]()
for (var i=0; i < users!.count; i++) {
let user = User(user: users?[i] as? Dictionary<String, AnyObject>)
self.users?[user!.id!] = user
}
}
private func enumerateChannels(channels: Array<AnyObject>?) {
self.channels = [String: Channel]()
for (var i=0; i < channels!.count; i++) {
let channel = Channel(channel: channels?[i] as? Dictionary<String, AnyObject>)
self.channels?[channel!.id!] = channel
}
}
private func enumerateGroups(groups: Array<AnyObject>?) {
for (var i=0; i < groups!.count; i++) {
let group = Channel(channel: groups?[i] as? Dictionary<String, AnyObject>)
self.channels?[group!.id!] = group
}
}
private func enumerateDMs(dms: Array<AnyObject>?) {
for (var i=0; i < dms!.count; i++) {
let dm = Channel(channel: dms?[i] as? Dictionary<String, AnyObject>)
self.channels?[dm!.id!] = dm
}
}
private func enumerateBots(bots: Array<AnyObject>?) {
self.bots = [String: Bot]()
for (var i=0; i < bots?.count; i++) {
let bot = Bot(bot: bots?[i] as? Dictionary<String, AnyObject>)
self.bots?[bot!.id!] = bot
}
}
// MARK: - Convenience methods
public func IDForChannelName(name: String) -> String? {
for channel in channels! {
if (channel.1.name == name) {
return channel.1.id!
private func enumerateUsers(users: [AnyObject]?) {
if let users = users {
for user in users {
let u = User(user: user as? [String: AnyObject])
self.users[u!.id!] = u
}
}
return nil
}
private func enumerateChannels(channels: [AnyObject]?) {
if let channels = channels {
for channel in channels {
let c = Channel(channel: channel as? [String: AnyObject])
self.channels[c!.id!] = c
}
}
}
private func enumerateGroups(groups: [AnyObject]?) {
if let groups = groups {
for group in groups {
let g = Channel(channel: group as? [String: AnyObject])
self.channels[g!.id!] = g
}
}
}
private func enumerateIMs(ims: [AnyObject]?) {
if let ims = ims {
for im in ims {
let i = Channel(channel: im as? [String: AnyObject])
self.channels[i!.id!] = i
}
}
}
private func enumerateMPIMs(mpims: [AnyObject]?) {
if let mpims = mpims {
for mpim in mpims {
let m = Channel(channel: mpim as? [String: AnyObject])
self.channels[m!.id!] = m
}
}
}
private func enumerateBots(bots: [AnyObject]?) {
if let bots = bots {
for bot in bots {
let b = Bot(bot: bot as? [String: AnyObject])
self.bots[b!.id!] = b
}
}
}
private func enumerateSubteams(subteams: [String: AnyObject]?) {
if let subteams = subteams {
if let all = subteams["all"] as? [[String: AnyObject]] {
for item in all {
let u = UserGroup(userGroup: item)
self.userGroups[u!.id!] = u
}
}
if let auth = subteams["self"] as? [String] {
for item in auth {
authenticatedUser?.userGroups = [String: String]()
authenticatedUser?.userGroups![item] = item
}
}
}
}
// MARK: - WebSocketDelegate
public func websocketDidConnect(socket: WebSocket) {
print("Connected.")
}
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
connected = false
authenticated = false
webSocket = nil
print("Disconnected: \(error)")
if let delegate = slackEventsDelegate {
delegate.clientDisconnected()
}
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
@@ -195,8 +233,7 @@ public class Client: WebSocketDelegate {
return
}
do {
try EventDispatcher.eventDispatcher(NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! Dictionary<String, AnyObject>)
print(try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary)
try EventDispatcher.eventDispatcher(NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! [String: AnyObject])
}
catch _ {
@@ -204,7 +241,6 @@ public class Client: WebSocketDelegate {
}
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
print("Data: \(data)")
}
}
+38 -26
View File
@@ -1,7 +1,7 @@
//
// Message.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -34,11 +34,13 @@ internal enum EventType: String {
case ChannelArchive = "channel_archive"
case ChannelUnarchive = "channel_unarchive"
case ChannelHistoryChanged = "channel_history_changed"
case DMCreated = "im_created"
case DMOpen = "im_open"
case DMClose = "im_close"
case DMMarked = "im_marked"
case DMHistoryChanged = "im_history_changed"
case DNDUpdated = "dnd_updated"
case DNDUpatedUser = "dnd_updated_user"
case IMCreated = "im_created"
case IMOpen = "im_open"
case IMClose = "im_close"
case IMMarked = "im_marked"
case IMHistoryChanged = "im_history_changed"
case GroupJoined = "group_joined"
case GroupLeft = "group_left"
case GroupOpen = "group_open"
@@ -80,6 +82,10 @@ internal enum EventType: String {
case BotChanged = "bot_changed"
case AccountsChanged = "accounts_changed"
case TeamMigrationStarted = "team_migration_started"
case SubteamCreated = "subteam_created"
case SubteamUpdated = "subteam_updated"
case SubteamSelfAdded = "subteam_self_added"
case SubteamSelfRemoved = "subteam_self_removed"
case Ok = "ok"
case Error = "error"
}
@@ -112,7 +118,7 @@ internal enum MessageSubtype: String {
internal struct Event {
let type: EventType
let type: EventType?
let ts: String?
let subtype: String?
let channelID: String?
@@ -126,14 +132,14 @@ internal struct Event {
let fileID: String?
let presence: String?
let name: String?
let value: String?
let value: AnyObject?
let plan: String?
let url: String?
let domain: String?
let emailDomain: String?
let reaction: String?
let replyTo: String?
let reactions: [Dictionary<String, AnyObject>]?
let reactions: [[String: AnyObject]]?
let edited: Edited?
let bot: Bot?
let channel: Channel?
@@ -143,12 +149,15 @@ internal struct Event {
let message: Message?
let nestedMessage: Message?
let item: Item?
let dndStatus: DoNotDisturbStatus?
let subteam: UserGroup?
let subteamID: String?
init(event:Dictionary<String, AnyObject>) {
init(event:[String: AnyObject]) {
if let eventType = event["type"] as? String {
type = EventType(rawValue:eventType)!
type = EventType(rawValue:eventType)
} else {
type = EventType(rawValue: "ok")!
type = EventType(rawValue: "ok")
}
ts = event["ts"] as? String
subtype = event["subtype"] as? String
@@ -163,43 +172,46 @@ internal struct Event {
fileID = event["file_id"] as? String
presence = event["presence"] as? String
name = event["name"] as? String
value = event["value"] as? String
value = event["value"]
plan = event["plan"] as? String
url = event["url"] as? String
domain = event["domain"] as? String
emailDomain = event["email_domain"] as? String
reaction = event["reaction"] as? String
replyTo = event["reply_to"] as? String
reactions = event["reactions"] as? [Dictionary<String, AnyObject>]
bot = Bot(bot: event["bot"] as? Dictionary<String, AnyObject>)
edited = Edited(edited:event["edited"] as? Dictionary<String, AnyObject>)
item = Item(item: event["item"] as? Dictionary<String, AnyObject>)
reactions = event["reactions"] as? [[String: AnyObject]]
bot = Bot(bot: event["bot"] as? [String: AnyObject])
edited = Edited(edited:event["edited"] as? [String: AnyObject])
dndStatus = DoNotDisturbStatus(status: event["dnd_status"] as? [String: AnyObject])
item = Item(item: event["item"] as? [String: AnyObject])
subteam = UserGroup(userGroup: event["subteam"] as? [String: AnyObject])
subteamID = event["subteam_id"] as? String
message = Message(message: event)
nestedMessage = Message(message: event["message"] as? Dictionary<String, AnyObject>)
nestedMessage = Message(message: event["message"] as? [String: AnyObject])
// Comment, Channel, User, and File can come across as Strings or Dictionaries
if (Comment(comment: event["comment"] as? Dictionary<String, AnyObject>) == nil) {
if (Comment(comment: event["comment"] as? [String: AnyObject])?.id == nil) {
comment = Comment(id: event["comment"] as? String)
} else {
comment = Comment(comment: event["comment"] as? Dictionary<String, AnyObject>)
comment = Comment(comment: event["comment"] as? [String: AnyObject])
}
if (User(user: event["user"] as? Dictionary<String, AnyObject>)?.id == nil) {
if (User(user: event["user"] as? [String: AnyObject])?.id == nil) {
user = User(id: event["user"] as? String)
} else {
user = User(user: event["user"] as? Dictionary<String, AnyObject>)
user = User(user: event["user"] as? [String: AnyObject])
}
if (File(file: event["file"] as? Dictionary<String, AnyObject>)?.id == nil) {
if (File(file: event["file"] as? [String: AnyObject])?.id == nil) {
file = File(id: event["file"] as? String)
} else {
file = File(file: event["file"] as? Dictionary<String, AnyObject>)
file = File(file: event["file"] as? [String: AnyObject])
}
if (Channel(channel: event["channel"] as? Dictionary<String, AnyObject>)?.id == nil) {
if (Channel(channel: event["channel"] as? [String: AnyObject])?.id == nil) {
channel = Channel(id: event["channel"] as? String)
} else {
channel = Channel(channel: event["channel"] as? Dictionary<String, AnyObject>)
channel = Channel(channel: event["channel"] as? [String: AnyObject])
}
}
+101
View File
@@ -0,0 +1,101 @@
//
// EventDelegate.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public protocol SlackEventsDelegate {
func clientConnected()
func clientDisconnected()
func preferenceChanged(preference: String, value: AnyObject)
func userChanged(user: User)
func presenceChanged(user: User?, presence: String?)
func manualPresenceChanged(user: User?, presence: String?)
func botEvent(bot: Bot)
}
public protocol MessageEventsDelegate {
func messageSent(message: Message)
func messageReceived(message: Message)
func messageChanged(message: Message)
func messageDeleted(message: Message?)
}
public protocol ChannelEventsDelegate {
func userTyping(channel: Channel?, user: User?)
func channelMarked(channel: Channel, timestamp: String?)
func channelCreated(channel: Channel)
func channelDeleted(channel: Channel)
func channelRenamed(channel: Channel)
func channelArchived(channel: Channel)
func channelHistoryChanged(channel: Channel)
func channelJoined(channel: Channel)
func channelLeft(channel: Channel)
}
public protocol DoNotDisturbEventsDelegate {
func doNotDisturbUpdated(dndStatus: DoNotDisturbStatus)
func doNotDisturbUserUpdated(dndStatus: DoNotDisturbStatus, user: User?)
}
public protocol GroupEventsDelegate {
func groupOpened(group: Channel)
}
public protocol FileEventsDelegate {
func fileProcessed(file: File)
func fileMadePrivate(file: File)
func fileDeleted(file: File)
func fileCommentAdded(file: File, comment: Comment)
func fileCommentEdited(file: File, comment: Comment)
func fileCommentDeleted(file: File, comment: Comment)
}
public protocol PinEventsDelegate {
func itemPinned(item: Item?, channel: Channel?)
func itemUnpinned(item: Item?, channel: Channel?)
}
public protocol StarEventsDelegate {
func itemStarred(item: Item, star: Bool)
}
public protocol ReactionEventsDelegate {
func reactionAdded(reaction: String?, item: Item?)
func reactionRemoved(reaction: String?, item: Item?)
}
public protocol TeamEventsDelegate {
func teamJoined(user: User)
func teamPlanChanged(plan: String)
func teamPreferencesChanged(preference: String, value: AnyObject)
func teamNameChanged(name: String)
func teamDomainChanged(domain: String)
func teamEmailDomainChanged(domain: String)
func teamEmojiChanged()
}
public protocol SubteamEventsDelegate {
func subteamEvent(userGroup: UserGroup)
func subteamSelfAdded(subteamID: String)
func subteamSelfRemoved(subteamID: String)
}
+117 -153
View File
@@ -1,7 +1,7 @@
//
// EventDispatcher.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,157 +23,124 @@
internal struct EventDispatcher {
static func eventDispatcher(event:Dictionary<String, AnyObject>) {
static func eventDispatcher(event: [String: AnyObject]) {
let event = Event(event: event)
switch event.type {
case .Hello:
EventHandler.connected()
break
case .Ok:
EventHandler.messageSent(event)
break
case .Message:
if (event.subtype != nil) {
messageDispatcher(event)
} else {
EventHandler.messageReceived(event)
if let type = event.type {
switch type {
case .Hello:
EventHandler.connected()
case .Ok:
EventHandler.messageSent(event)
case .Message:
if (event.subtype != nil) {
messageDispatcher(event)
} else {
EventHandler.messageReceived(event)
}
case .UserTyping:
EventHandler.userTyping(event)
case .ChannelMarked, .IMMarked, .GroupMarked:
EventHandler.channelMarked(event)
case .ChannelCreated, .IMCreated:
EventHandler.channelCreated(event)
case .ChannelJoined, .GroupJoined:
EventHandler.channelJoined(event)
case .ChannelLeft, .GroupLeft:
EventHandler.channelLeft(event)
case .ChannelDeleted:
EventHandler.channelDeleted(event)
case .ChannelRenamed, .GroupRename:
EventHandler.channelRenamed(event)
case .ChannelArchive, .GroupArchive:
EventHandler.channelArchived(event, archived: true)
case .ChannelUnarchive, .GroupUnarchive:
EventHandler.channelArchived(event, archived: false)
case .ChannelHistoryChanged, .IMHistoryChanged, .GroupHistoryChanged:
EventHandler.channelHistoryChanged(event)
case .DNDUpdated:
EventHandler.doNotDisturbUpdated(event)
case .DNDUpatedUser:
EventHandler.doNotDisturbUserUpdated(event)
case .IMOpen, .GroupOpen:
EventHandler.open(event, open: true)
case .IMClose, .GroupClose:
EventHandler.open(event, open: false)
case .FileCreated:
EventHandler.processFile(event)
case .FileShared:
EventHandler.processFile(event)
case .FileUnshared:
EventHandler.processFile(event)
case .FilePublic:
EventHandler.processFile(event)
case .FilePrivate:
EventHandler.filePrivate(event)
case .FileChanged:
EventHandler.processFile(event)
case .FileDeleted:
EventHandler.deleteFile(event)
case .FileCommentAdded:
EventHandler.fileCommentAdded(event)
case .FileCommentEdited:
EventHandler.fileCommentEdited(event)
case .FileCommentDeleted:
EventHandler.fileCommentDeleted(event)
case .PinAdded:
EventHandler.pinAdded(event)
case .PinRemoved:
EventHandler.pinRemoved(event)
case .PresenceChange:
EventHandler.presenceChange(event)
case .ManualPresenceChange:
EventHandler.manualPresenceChange(event)
case .PrefChange:
EventHandler.changePreference(event)
case .UserChange:
EventHandler.userChange(event)
case .TeamJoin:
EventHandler.teamJoin(event)
case .StarAdded:
EventHandler.itemStarred(event, star: true)
case .StarRemoved:
EventHandler.itemStarred(event, star: false)
case .ReactionAdded:
EventHandler.addedReaction(event)
case .ReactionRemoved:
EventHandler.removedReaction(event)
case .EmojiChanged:
EventHandler.emojiChanged(event)
case .CommandsChanged:
// Not implemented per Slack documentation.
break
case .TeamPlanChange:
EventHandler.teamPlanChange(event)
case .TeamPrefChange:
EventHandler.teamPreferenceChange(event)
case .TeamRename:
EventHandler.teamNameChange(event)
case .TeamDomainChange:
EventHandler.teamDomainChange(event)
case .EmailDomainChange:
EventHandler.emailDomainChange(event)
case .BotAdded:
EventHandler.bot(event)
case .BotChanged:
EventHandler.bot(event)
case .AccountsChanged:
// Not implemented per Slack documentation.
break
case .TeamMigrationStarted:
Client.sharedInstance.connect()
case .SubteamCreated, .SubteamUpdated:
EventHandler.subteam(event)
case .SubteamSelfAdded:
EventHandler.subteamAddedSelf(event)
case.SubteamSelfRemoved:
EventHandler.subteamRemovedSelf(event)
case .Error:
print("Error: \(event)")
break
}
break
case .UserTyping:
EventHandler.userTyping(event)
break
case .ChannelMarked, .DMMarked, .GroupMarked:
EventHandler.channelMarked(event)
break
case .ChannelCreated, .DMCreated:
EventHandler.channelCreated(event)
break
case .ChannelJoined, .GroupJoined:
EventHandler.channelJoined(event)
break
case .ChannelLeft, .GroupLeft:
EventHandler.channelLeft(event)
break
case .ChannelDeleted:
EventHandler.channelDeleted(event)
break
case .ChannelRenamed, .GroupRename:
EventHandler.channelRenamed(event)
break
case .ChannelArchive, .GroupArchive:
EventHandler.channelArchived(event, archived: true)
break
case .ChannelUnarchive, .GroupUnarchive:
EventHandler.channelArchived(event, archived: false)
break
case .ChannelHistoryChanged, .DMHistoryChanged, .GroupHistoryChanged:
EventHandler.channelHistoryChanged(event)
break
case .DMOpen, .GroupOpen:
EventHandler.open(event, open: true)
break
case .DMClose, .GroupClose:
EventHandler.open(event, open: false)
break
case .FileCreated:
EventHandler.processFile(event)
break
case .FileShared:
EventHandler.processFile(event)
break
case .FileUnshared:
EventHandler.processFile(event)
break
case .FilePublic:
EventHandler.processFile(event)
break
case .FilePrivate:
EventHandler.filePrivate(event)
break
case .FileChanged:
EventHandler.processFile(event)
break
case .FileDeleted:
EventHandler.deleteFile(event)
break
case .FileCommentAdded:
EventHandler.fileCommentAdded(event)
break
case .FileCommentEdited:
EventHandler.fileCommentEdited(event)
break
case .FileCommentDeleted:
EventHandler.fileCommentDeleted(event)
break
case .PinAdded:
EventHandler.pinAdded(event)
break
case .PinRemoved:
EventHandler.pinRemoved(event)
break
case .PresenceChange:
EventHandler.presenceChange(event)
break
case .ManualPresenceChange:
EventHandler.manualPresenceChange(event)
break
case .PrefChange:
EventHandler.changePreference(event)
break
case .UserChange:
EventHandler.userChange(event)
break
case .TeamJoin:
EventHandler.teamJoin(event)
break
case .StarAdded:
EventHandler.messageStarred(event, star: true)
break
case .StarRemoved:
EventHandler.messageStarred(event, star: false)
break
case .ReactionAdded:
EventHandler.addedReaction(event)
break
case .ReactionRemoved:
EventHandler.removedReaction(event)
break
case .EmojiChanged:
EventHandler.emojiChanged(event)
break
case .CommandsChanged:
// Not implemented per Slack documentation.
break
case .TeamPlanChange:
EventHandler.teamPlanChange(event)
break
case .TeamPrefChange:
EventHandler.teamPreferenceChange(event)
break
case .TeamRename:
EventHandler.teamNameChange(event)
break
case .TeamDomainChange:
EventHandler.teamDomainChange(event)
break
case .EmailDomainChange:
EventHandler.emailDomainChange(event)
break
case .BotAdded:
EventHandler.bot(event)
break
case .BotChanged:
EventHandler.bot(event)
break
case .AccountsChanged:
// Not implemented per Slack documentation.
break
case .TeamMigrationStarted:
Client.sharedInstance.connect()
break
case .Error:
break
}
}
@@ -182,13 +149,10 @@ internal struct EventDispatcher {
switch subtype {
case .MessageChanged:
EventHandler.messageChanged(event)
break
case .MessageDeleted:
EventHandler.messageDeleted(event)
break
default:
EventHandler.messageReceived(event)
break
}
}
+381 -97
View File
@@ -1,7 +1,7 @@
//
// EventHandler.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -28,210 +28,415 @@ internal struct EventHandler {
//MARK: - Initial connection
static func connected() {
Client.sharedInstance.connected = true
if let delegate = Client.sharedInstance.slackEventsDelegate {
delegate.clientConnected()
}
}
//MARK: - Messages
static func messageSent(event: Event) {
if let reply = event.replyTo {
if let message = Client.sharedInstance.sentMessages[reply] {
message.ts = event.ts
message.text = event.text
Client.sharedInstance.channels?[message.channel!]?.messages[message.ts!] = message
if let reply = event.replyTo, message = Client.sharedInstance.sentMessages[reply], channel = message.channel, ts = message.ts {
message.ts = event.ts
message.text = event.text
Client.sharedInstance.channels[channel]?.messages[ts] = message
if let delegate = Client.sharedInstance.messageEventsDelegate {
delegate.messageSent(message)
}
}
}
static func messageReceived(event: Event) {
if let channel = event.channel,
message = event.message
{
Client.sharedInstance.channels?[channel.id!]?.messages[message.ts!] = message
if let channel = event.channel, message = event.message, id = channel.id, ts = message.ts {
Client.sharedInstance.channels[id]?.messages[ts] = message
if let delegate = Client.sharedInstance.messageEventsDelegate {
delegate.messageReceived(message)
}
}
}
static func messageChanged(event: Event) {
if let id = event.channel?.id {
if let nested = event.nestedMessage {
Client.sharedInstance.channels?[id]?.messages[nested.ts!] = nested
if let id = event.channel?.id, nested = event.nestedMessage, ts = nested.ts {
Client.sharedInstance.channels[id]?.messages[ts] = nested
if let delegate = Client.sharedInstance.messageEventsDelegate {
delegate.messageChanged(nested)
}
}
}
static func messageDeleted(event: Event) {
if let id = event.channel?.id {
if let key = event.message?.deletedTs {
Client.sharedInstance.channels?[id]?.messages.removeValueForKey(key)
if let id = event.channel?.id, key = event.message?.deletedTs {
let message = Client.sharedInstance.channels[id]?.messages[key]
Client.sharedInstance.channels[id]?.messages.removeValueForKey(key)
if let delegate = Client.sharedInstance.messageEventsDelegate {
delegate.messageDeleted(message)
}
}
}
//MARK: - Channels
static func userTyping(event: Event) {
if (!Client.sharedInstance.channels![event.channel!.id!]!.usersTyping.contains(event.user!.id!)) {
Client.sharedInstance.channels?[event.channel!.id!]?.usersTyping.append(event.user!.id!)
}
let timeout = dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC)))
dispatch_after(timeout, dispatch_get_main_queue()) {
if let index = Client.sharedInstance.channels?[event.channel!.id!]?.usersTyping.indexOf(event.user!.id!) {
Client.sharedInstance.channels?[event.channel!.id!]?.usersTyping.removeAtIndex(index)
if let channelID = event.channel?.id, userID = event.user?.id {
if let _ = Client.sharedInstance.channels[channelID] {
if (!Client.sharedInstance.channels[channelID]!.usersTyping.contains(userID)) {
Client.sharedInstance.channels[channelID]?.usersTyping.append(userID)
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.userTyping(event.channel, user: event.user)
}
}
}
let timeout = dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC)))
dispatch_after(timeout, dispatch_get_main_queue()) {
if let index = Client.sharedInstance.channels[channelID]?.usersTyping.indexOf(userID) {
Client.sharedInstance.channels[channelID]?.usersTyping.removeAtIndex(index)
}
}
}
}
static func channelMarked(event: Event) {
if let channel = event.channel {
Client.sharedInstance.channels?[channel.id!]?.lastRead = event.ts
if let channel = event.channel, id = channel.id {
Client.sharedInstance.channels[id]?.lastRead = event.ts
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelMarked(channel, timestamp: event.ts)
}
}
//TO-DO: Recalculate unreads
//TODO: Recalculate unreads
}
static func channelCreated(event: Event) {
if let channel = event.channel {
Client.sharedInstance.channels?[channel.id!] = channel
if let channel = event.channel, id = channel.id {
Client.sharedInstance.channels[id] = channel
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelCreated(channel)
}
}
}
static func channelDeleted(event: Event) {
if let channel = event.channel {
Client.sharedInstance.channels?.removeValueForKey(channel.id!)
if let channel = event.channel, id = channel.id {
Client.sharedInstance.channels.removeValueForKey(id)
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelDeleted(channel)
}
}
}
static func channelJoined(event: Event) {
if let channel = event.channel {
Client.sharedInstance.channels?[channel.id!]?.members.append(Client.sharedInstance.authenticatedUser!.id!)
if let channel = event.channel, id = channel.id {
Client.sharedInstance.channels[id] = event.channel
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelJoined(channel)
}
}
}
static func channelLeft(event: Event) {
if let channel = event.channel {
if let index = Client.sharedInstance.channels?[channel.id!]?.members.indexOf(Client.sharedInstance.authenticatedUser!.id!) {
Client.sharedInstance.channels?[channel.id!]?.members.removeAtIndex(index)
if let channel = event.channel, id = channel.id, userID = Client.sharedInstance.authenticatedUser?.id {
if let index = Client.sharedInstance.channels[id]?.members.indexOf(userID) {
Client.sharedInstance.channels[id]?.members.removeAtIndex(index)
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelLeft(channel)
}
}
}
}
static func channelRenamed(event: Event) {
if let channel = event.channel {
Client.sharedInstance.channels?[channel.id!]?.name = channel.name
if let channel = event.channel, id = channel.id {
Client.sharedInstance.channels[id]?.name = channel.name
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelRenamed(channel)
}
}
}
static func channelArchived(event: Event, archived: Bool) {
if let channel = event.channel {
Client.sharedInstance.channels?[channel.id!]?.isArchived = archived
if let channel = event.channel, id = channel.id {
Client.sharedInstance.channels[id]?.isArchived = archived
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelArchived(channel)
}
}
}
static func channelHistoryChanged(event: Event) {
//TO-DO: Reload chat history if there are any cached messages before latest
if let channel = event.channel {
//TODO: Reload chat history if there are any cached messages before latest
if let delegate = Client.sharedInstance.channelEventsDelegate {
delegate.channelHistoryChanged(channel)
}
}
}
//MARK: - DM & Group Open/Close
//MARK: - Do Not Disturb
static func doNotDisturbUpdated(event: Event) {
if let dndStatus = event.dndStatus {
Client.sharedInstance.authenticatedUser?.doNotDisturbStatus = dndStatus
if let delegate = Client.sharedInstance.doNotDisturbEventsDelegate {
delegate.doNotDisturbUpdated(dndStatus)
}
}
}
static func doNotDisturbUserUpdated(event: Event) {
if let dndStatus = event.dndStatus, user = event.user, id = user.id {
Client.sharedInstance.users[id]?.doNotDisturbStatus = dndStatus
if let delegate = Client.sharedInstance.doNotDisturbEventsDelegate {
delegate.doNotDisturbUserUpdated(dndStatus, user: user)
}
}
}
//MARK: - IM & Group Open/Close
static func open(event: Event, open: Bool) {
if let channel = event.channel {
Client.sharedInstance.channels?[channel.id!]?.isOpen = open
if let channel = event.channel, id = channel.id {
Client.sharedInstance.channels[id]?.isOpen = open
if let delegate = Client.sharedInstance.groupEventsDelegate {
delegate.groupOpened(channel)
}
}
}
//MARK: - Files
static func processFile(event: Event) {
if let file = event.file {
Client.sharedInstance.files?[file.id!] = file
if let file = event.file, id = file.id {
if let comment = file.initialComment, commentID = comment.id {
if Client.sharedInstance.files[id]?.comments[commentID] == nil {
Client.sharedInstance.files[id]?.comments[commentID] = comment
}
}
Client.sharedInstance.files[id] = file
if let delegate = Client.sharedInstance.fileEventsDelegate {
delegate.fileProcessed(file)
}
}
}
static func filePrivate(event: Event) {
if let file = event.file {
Client.sharedInstance.files?[file.id!]?.isPublic = false
if let file = event.file, id = file.id {
Client.sharedInstance.files[id]?.isPublic = false
if let delegate = Client.sharedInstance.fileEventsDelegate {
delegate.fileMadePrivate(file)
}
}
}
static func deleteFile(event: Event) {
if let file = event.file {
Client.sharedInstance.files?.removeValueForKey(file.id!)
if let file = event.file, id = file.id {
if Client.sharedInstance.files[id] != nil {
Client.sharedInstance.files.removeValueForKey(id)
}
if let delegate = Client.sharedInstance.fileEventsDelegate {
delegate.fileDeleted(file)
}
}
}
static func fileCommentAdded(event: Event) {
if let file = event.file {
if let comment = event.comment {
Client.sharedInstance.files?[file.id!]?.comments?.append(comment)
if let file = event.file, id = file.id, comment = event.comment, commentID = comment.id {
Client.sharedInstance.files[id]?.comments[commentID] = comment
if let delegate = Client.sharedInstance.fileEventsDelegate {
delegate.fileCommentAdded(file, comment: comment)
}
}
}
static func fileCommentEdited(event: Event) {
if let file = event.file {
if let commentEdit = event.comment {
if let comments = Client.sharedInstance.files?[file.id!]?.comments?.filter({$0.id == commentEdit.id}) {
if var comment = comments.first {
comment.comment = commentEdit.comment
comment.timestamp = commentEdit.timestamp
}
}
if let file = event.file, id = file.id, comment = event.comment, commentID = comment.id {
Client.sharedInstance.files[id]?.comments[commentID]?.comment = comment.comment
if let delegate = Client.sharedInstance.fileEventsDelegate {
delegate.fileCommentEdited(file, comment: comment)
}
}
}
static func fileCommentDeleted(event: Event) {
if let file = event.file {
if let comment = event.comment {
if let comments = Client.sharedInstance.files?[file.id!]?.comments?.filter({$0.id != comment.id}) {
Client.sharedInstance.files?[file.id!]?.comments = comments
}
if let file = event.file, id = file.id, comment = event.comment, commentID = comment.id {
Client.sharedInstance.files[id]?.comments.removeValueForKey(commentID)
if let delegate = Client.sharedInstance.fileEventsDelegate {
delegate.fileCommentDeleted(file, comment: comment)
}
}
}
//MARK: - Pins
static func pinAdded(event: Event) {
if let id = event.channelID {
Client.sharedInstance.channels?[id]?.pinnedItems.append(event.item!)
if let id = event.channelID, item = event.item {
Client.sharedInstance.channels[id]?.pinnedItems.append(item)
if let delegate = Client.sharedInstance.pinEventsDelegate {
delegate.itemPinned(item, channel: Client.sharedInstance.channels[id])
}
}
}
static func pinRemoved(event: Event) {
if let id = event.channelID {
if let pins = Client.sharedInstance.channels?[id]?.pinnedItems.filter({$0 != event.item}) {
Client.sharedInstance.channels?[id]?.pinnedItems = pins
if let pins = Client.sharedInstance.channels[id]?.pinnedItems.filter({$0 != event.item}) {
Client.sharedInstance.channels[id]?.pinnedItems = pins
}
if let delegate = Client.sharedInstance.pinEventsDelegate {
delegate.itemUnpinned(event.item, channel: Client.sharedInstance.channels[id])
}
}
}
//MARK: - Stars
static func messageStarred(event: Event, star: Bool) {
if let item = event.item {
if let message = Client.sharedInstance.channels?[item.channel!]?.messages[item.message!.ts!] {
message.isStarred = star
static func itemStarred(event: Event, star: Bool) {
if let item = event.item, type = item.type {
switch type {
case "message":
starMessage(item, star: star)
case "file":
starFile(item, star: star)
case "file_comment":
starComment(item)
default:
break
}
if let delegate = Client.sharedInstance.starEventsDelegate {
delegate.itemStarred(item, star: star)
}
}
}
static func starMessage(item: Item, star: Bool) {
if let message = item.message, ts = message.ts, channel = item.channel {
if let _ = Client.sharedInstance.channels[channel]?.messages[ts] {
Client.sharedInstance.channels[channel]?.messages[ts]?.isStarred = star
}
}
}
static func starFile(item: Item, star: Bool) {
if let file = item.file, id = file.id {
Client.sharedInstance.files[id]?.isStarred = star
if let stars = Client.sharedInstance.files[id]?.stars {
if star == true {
Client.sharedInstance.files[id]?.stars = stars + 1
} else {
if stars > 0 {
Client.sharedInstance.files[id]?.stars = stars - 1
}
}
}
}
}
static func starComment(item: Item) {
if let file = item.file, id = file.id, comment = item.comment, commentID = comment.id {
Client.sharedInstance.files[id]?.comments[commentID] = comment
}
}
//MARK: - Reactions
static func addedReaction(event: Event) {
if let channel = event.item?.channel {
if let message = Client.sharedInstance.channels?[channel]?.messages[event.item!.ts!] {
if (message.reactions[event.reaction!]) == nil {
message.reactions[event.reaction!] = Reaction(name: event.reaction, user: event.user!.id!)
} else {
message.reactions[event.reaction!]?.users[event.user!.id!] = event.user!.id!
if let item = event.item, type = item.type, key = event.reaction, userID = event.user?.id {
switch type {
case "message":
if let channel = item.channel, ts = item.ts {
if let message = Client.sharedInstance.channels[channel]?.messages[ts] {
if (message.reactions[key]) == nil {
message.reactions[key] = Reaction(name: event.reaction, user: userID)
} else {
message.reactions[key]?.users[userID] = userID
}
}
}
case "file":
if let id = item.file?.id, var file = Client.sharedInstance.files[id] {
if file.reactions[key] == nil {
Client.sharedInstance.files[id]?.reactions[key] = Reaction(name: event.reaction, user: userID)
} else {
Client.sharedInstance.files[id]?.reactions[key]?.users[userID] = userID
}
}
case "file_comment":
if let id = item.file?.id, var file = Client.sharedInstance.files[id], let commentID = item.fileCommentID {
if file.comments[commentID]?.reactions[key] == nil {
Client.sharedInstance.files[id]?.comments[commentID]?.reactions[key] = Reaction(name: event.reaction, user: userID)
} else {
Client.sharedInstance.files[id]?.comments[commentID]?.reactions[key]?.users[userID] = userID
}
}
break
default:
break
}
if let delegate = Client.sharedInstance.reactionEventsDelegate {
delegate.reactionAdded(event.reaction, item: event.item)
}
}
}
static func removedReaction(event: Event) {
if let channel = event.item?.channel {
if let message = Client.sharedInstance.channels?[channel]?.messages[event.item!.ts!] {
if (message.reactions[event.reaction!]) != nil {
message.reactions[event.reaction!]?.users.removeValueForKey(event.user!.id!)
if let item = event.item, type = item.type, key = event.reaction, userID = event.user?.id {
switch type {
case "message":
if let channel = item.channel, ts = item.ts {
if let message = Client.sharedInstance.channels[channel]?.messages[ts] {
if (message.reactions[key]) != nil {
message.reactions[key]?.users.removeValueForKey(userID)
}
if (message.reactions[key]?.users.count == 0) {
message.reactions.removeValueForKey(key)
}
}
}
if (message.reactions[event.reaction!]?.users.count == 0) {
message.reactions.removeValueForKey(event.reaction!)
case "file":
if let itemFile = item.file, id = itemFile.id, var file = Client.sharedInstance.files[id] {
if file.reactions[key] != nil {
Client.sharedInstance.files[id]?.reactions[key]?.users.removeValueForKey(userID)
}
if Client.sharedInstance.files[id]?.reactions[key]?.users.count == 0 {
Client.sharedInstance.files[id]?.reactions.removeValueForKey(key)
}
}
case "file_comment":
if let id = item.file?.id, var file = Client.sharedInstance.files[id], let commentID = item.fileCommentID {
if file.comments[commentID]?.reactions[key] != nil {
Client.sharedInstance.files[id]?.comments[commentID]?.reactions[key]?.users.removeValueForKey(userID)
}
if Client.sharedInstance.files[id]?.comments[commentID]?.reactions[key]?.users.count == 0 {
Client.sharedInstance.files[id]?.comments[commentID]?.reactions.removeValueForKey(key)
}
}
break
default:
break
}
if let delegate = Client.sharedInstance.reactionEventsDelegate {
delegate.reactionAdded(event.reaction, item: event.item)
}
}
}
@@ -240,76 +445,155 @@ internal struct EventHandler {
static func changePreference(event: Event) {
if let name = event.name {
Client.sharedInstance.authenticatedUser?.preferences?[name] = event.value
if let delegate = Client.sharedInstance.slackEventsDelegate, value = event.value {
delegate.preferenceChanged(name, value: value)
}
}
}
//Mark: - User Change
static func userChange(event: Event) {
if var user = event.user {
user.preferences = Client.sharedInstance.users?[user.id!]?.preferences
Client.sharedInstance.users?[user.id!] = user
if var user = event.user, let id = user.id {
user.preferences = Client.sharedInstance.users[id]?.preferences
Client.sharedInstance.users[id] = user
if let delegate = Client.sharedInstance.slackEventsDelegate {
delegate.userChanged(user)
}
}
}
//MARK: - User Presence
static func presenceChange(event: Event) {
if let user = event.user {
Client.sharedInstance.users?[user.id!]?.presence = event.presence
if let user = event.user, id = user.id {
Client.sharedInstance.users[id]?.presence = event.presence
if let delegate = Client.sharedInstance.slackEventsDelegate {
delegate.presenceChanged(user, presence: event.presence)
}
}
}
//MARK: - Team
static func teamJoin(event: Event) {
if let user = event.user {
Client.sharedInstance.users?[user.id!] = user
if let user = event.user, id = user.id {
Client.sharedInstance.users[id] = user
if let delegate = Client.sharedInstance.teamEventsDelegate {
delegate.teamJoined(user)
}
}
}
static func teamPlanChange(event: Event) {
if let plan = event.plan {
Client.sharedInstance.team?.plan = plan
if let delegate = Client.sharedInstance.teamEventsDelegate {
delegate.teamPlanChanged(plan)
}
}
}
static func teamPreferenceChange(event: Event) {
if let name = event.name {
Client.sharedInstance.team?.prefs?[name] = event.value
if let delegate = Client.sharedInstance.teamEventsDelegate, value = event.value {
delegate.teamPreferencesChanged(name, value: value)
}
}
}
static func teamNameChange(event: Event) {
if let name = event.name {
Client.sharedInstance.team?.name = name
if let delegate = Client.sharedInstance.teamEventsDelegate {
delegate.teamNameChanged(name)
}
}
}
static func teamDomainChange(event: Event) {
if let domain = event.domain {
Client.sharedInstance.team?.domain = domain
if let delegate = Client.sharedInstance.teamEventsDelegate {
delegate.teamDomainChanged(domain)
}
}
}
static func emailDomainChange(event: Event) {
if let domain = event.emailDomain {
Client.sharedInstance.team?.emailDomain = domain
if let delegate = Client.sharedInstance.teamEventsDelegate {
delegate.teamEmailDomainChanged(domain)
}
}
}
//Mark: - Changed
static func emojiChanged(event: Event) {
//TODO: Call emoji.list here
if let delegate = Client.sharedInstance.teamEventsDelegate {
delegate.teamEmojiChanged()
}
}
//Mark: - Bots
//MARK: - Bots
static func bot(event: Event) {
if let bot = event.bot {
Client.sharedInstance.bots?[bot.id!] = bot
if let bot = event.bot, id = bot.id {
Client.sharedInstance.bots[id] = bot
if let delegate = Client.sharedInstance.slackEventsDelegate {
delegate.botEvent(bot)
}
}
}
//MARK: - Subteams
static func subteam(event: Event) {
if let subteam = event.subteam, id = subteam.id {
Client.sharedInstance.userGroups[id] = subteam
if let delegate = Client.sharedInstance.subteamEventsDelegate {
delegate.subteamEvent(subteam)
}
}
}
static func subteamAddedSelf(event: Event) {
if let subteamID = event.subteamID, _ = Client.sharedInstance.authenticatedUser?.userGroups {
Client.sharedInstance.authenticatedUser?.userGroups![subteamID] = subteamID
if let delegate = Client.sharedInstance.subteamEventsDelegate {
delegate.subteamSelfAdded(subteamID)
}
}
}
static func subteamRemovedSelf(event: Event) {
if let subteamID = event.subteamID {
Client.sharedInstance.authenticatedUser?.userGroups?.removeValueForKey(subteamID)
if let delegate = Client.sharedInstance.subteamEventsDelegate {
delegate.subteamSelfRemoved(subteamID)
}
}
}
//MARK: - Authenticated User
static func manualPresenceChange(event: Event) {
Client.sharedInstance.authenticatedUser?.presence = event.presence
if let delegate = Client.sharedInstance.slackEventsDelegate {
delegate.manualPresenceChanged(Client.sharedInstance.authenticatedUser, presence: event.presence)
}
}
}
+49 -55
View File
@@ -1,7 +1,7 @@
//
// File.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,51 +23,50 @@
public struct File {
let id: String?
let created: String?
let timeStamp: String?
let name: String?
let title: String?
let mimeType: String?
let fileType: String?
let prettyType: String?
let user: String?
let mode: String?
let editable: Bool?
let isExternal: Bool?
let externalType: String?
let size: Int?
let url: String?
let urlDownload: String?
let urlPrivate: String?
let urlPrivateDownload: String?
let thumb64: String?
let thumb80: String?
let thumb360: String?
let thumb360gif: String?
let thumb360w: String?
let thumb360h: String?
let permalink: String?
let editLink: String?
let preview: String?
let previewHighlight: String?
let lines: Int?
let linesMore: Int?
public let id: String?
public let created: Int?
public let name: String?
public let title: String?
public let mimeType: String?
public let fileType: String?
public let prettyType: String?
public let user: String?
public let mode: String?
internal(set) public var editable: Bool?
public let isExternal: Bool?
public let externalType: String?
public let size: Int?
public let url: String?
public let urlDownload: String?
public let urlPrivate: String?
public let urlPrivateDownload: String?
public let thumb64: String?
public let thumb80: String?
public let thumb360: String?
public let thumb360gif: String?
public let thumb360w: String?
public let thumb360h: String?
public let permalink: String?
public let editLink: String?
public let preview: String?
public let previewHighlight: String?
public let lines: Int?
public let linesMore: Int?
internal(set) public var isPublic: Bool?
let publicSharedURL: Bool?
let channels: [String]?
let groups: [String]?
let dms: [String]?
let initialComment: Comment?
let stars: Int?
let isStarred: Bool?
let pinnedTo: [String]?
internal(set) public lazy var comments = [Comment]?()
internal(set) public var publicSharedURL: Bool?
internal(set) public var channels: [String]?
internal(set) public var groups: [String]?
internal(set) public var ims: [String]?
public let initialComment: Comment?
internal(set) public var stars: Int?
internal(set) public var isStarred: Bool?
internal(set) public var pinnedTo: [String]?
internal(set) public var comments = [String: Comment]()
internal(set) public var reactions = [String: Reaction]()
init?(file:Dictionary<String, AnyObject>?) {
init?(file:[String: AnyObject]?) {
id = file?["id"] as? String
created = file?["created"] as? String
timeStamp = file?["timestamp"] as? String
created = file?["created"] as? Int
name = file?["name"] as? String
title = file?["title"] as? String
mimeType = file?["mimetype"] as? String
@@ -99,17 +98,20 @@ public struct File {
publicSharedURL = file?["public_url_shared"] as? Bool
channels = file?["channels"] as? [String]
groups = file?["groups"] as? [String]
dms = file?["ims"] as? [String]
initialComment = Comment(comment: file?["initial_comment"] as? Dictionary<String, AnyObject>)
stars = file?["stars"] as? Int
ims = file?["ims"] as? [String]
initialComment = Comment(comment: file?["initial_comment"] as? [String: AnyObject])
stars = file?["num_stars"] as? Int
isStarred = file?["is_starred"] as? Bool
pinnedTo = file?["pinned_to"] as? [String]
if let reactions = file?["reactions"] as? [[String: AnyObject]] {
self.reactions = Reaction.reactionsFromArray(reactions)
}
}
init?(id:String?) {
self.id = id
created = nil
timeStamp = nil
name = nil
title = nil
mimeType = nil
@@ -117,7 +119,6 @@ public struct File {
prettyType = nil
user = nil
mode = nil
editable = nil
isExternal = nil
externalType = nil
size = nil
@@ -137,14 +138,7 @@ public struct File {
previewHighlight = nil
lines = nil
linesMore = nil
publicSharedURL = nil
channels = nil
groups = nil
dms = nil
initialComment = nil
stars = nil
isStarred = nil
pinnedTo = nil
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Peter Zignego. All rights reserved.</string>
<string>Copyright © 2016 Peter Zignego. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
+30 -30
View File
@@ -1,7 +1,7 @@
//
// Message.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -29,32 +29,32 @@ public enum ItemType: String {
}
public class Message {
let type = "message"
let subtype: String?
var ts: String?
let user: String?
let channel: String?
let hidden: Bool?
internal(set) public var text: String?
let botID: String?
let username: String?
let icons: Dictionary<String, AnyObject>?
let deletedTs: String?
let purpose: String?
let topic: String?
let name: String?
let members: [String]?
let oldName: String?
let upload: Bool?
let itemType: String?
internal(set) public var isStarred: Bool?
let pinnedTo: [String]?
let comment: Comment?
let file: File?
internal(set) public lazy var reactions = Dictionary<String, Reaction>()
init?(message: Dictionary<String, AnyObject>?) {
public let type = "message"
public let subtype: String?
internal(set) public var ts: String?
public let user: String?
public let channel: String?
internal(set) public var hidden: Bool?
internal(set) public var text: String?
public let botID: String?
public let username: String?
public let icons: [String: AnyObject]?
public let deletedTs: String?
internal(set) var purpose: String?
internal(set) var topic: String?
internal(set) var name: String?
internal(set) var members: [String]?
internal(set) var oldName: String?
public let upload: Bool?
public let itemType: String?
internal(set) public var isStarred: Bool?
internal(set) var pinnedTo: [String]?
public let comment: Comment?
public let file: File?
internal(set) public var reactions = [String: Reaction]()
init?(message: [String: AnyObject]?) {
subtype = message?["subtype"] as? String
ts = message?["ts"] as? String
user = message?["user"] as? String
@@ -63,7 +63,7 @@ public class Message {
text = message?["text"] as? String
botID = message?["bot_id"] as? String
username = message?["username"] as? String
icons = message?["icons"] as? Dictionary<String, AnyObject>
icons = message?["icons"] as? [String: AnyObject]
deletedTs = message?["deleted_ts"] as? String
purpose = message?["purpose"] as? String
topic = message?["topic"] as? String
@@ -74,9 +74,9 @@ public class Message {
itemType = message?["item_type"] as? String
isStarred = message?["is_starred"] as? Bool
pinnedTo = message?["pinned_to"] as? [String]
comment = Comment(comment: message?["comment"] as? Dictionary<String, AnyObject>)
file = File(file: message?["file"] as? Dictionary<String, AnyObject>)
if let messageReactions = message?["reactions"] as? [Dictionary<String, AnyObject>] {
comment = Comment(comment: message?["comment"] as? [String: AnyObject])
file = File(file: message?["file"] as? [String: AnyObject])
if let messageReactions = message?["reactions"] as? [[String: AnyObject]] {
for react in messageReactions {
let reaction = Reaction(reaction: react)
self.reactions[reaction!.name!] = reaction
+1 -1
View File
@@ -1,7 +1,7 @@
//
// SlackKit.h
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
+5 -5
View File
@@ -1,7 +1,7 @@
//
// Team.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,23 +23,23 @@
public struct Team {
let id: String
public let id: String
internal(set) public var name: String?
internal(set) public var emailDomain: String?
internal(set) public var domain: String?
internal(set) public var messageEditWindowMinutes: Int?
internal(set) public var overStorageLimit: Bool?
internal(set) public var prefs: Dictionary<String, AnyObject>?
internal(set) public var prefs: [String: AnyObject]?
internal(set) public var plan: String?
internal init?(team: Dictionary<String, AnyObject>?) {
internal init?(team: [String: AnyObject]?) {
id = team?["id"] as! String
name = team?["id"] as? String
emailDomain = team?["email_domain"] as? String
domain = team?["domain"] as? String
messageEditWindowMinutes = team?["mesg_edit_window_mins"] as? Int
overStorageLimit = team?["over_storage_limit"] as? Bool
prefs = team?["prefs"] as? Dictionary<String, AnyObject>
prefs = team?["prefs"] as? [String: AnyObject]
plan = team?["plan"] as? String
}
}
+86 -29
View File
@@ -1,7 +1,7 @@
//
// Types.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,10 +23,10 @@
// MARK: - Edited
public struct Edited {
let user: String?
let ts: String?
public let user: String?
public let ts: String?
internal init?(edited:Dictionary<String, AnyObject>?) {
internal init?(edited:[String: AnyObject]?) {
user = edited?["user"] as? String
ts = edited?["ts"] as? String
}
@@ -34,10 +34,10 @@ public struct Edited {
// MARK: - Reaction
public struct Reaction {
let name: String?
internal(set) public lazy var users = Dictionary<String, String>()
public let name: String?
internal(set) public var users = [String: String]()
internal init?(reaction:Dictionary<String, AnyObject>?) {
internal init?(reaction:[String: AnyObject]?) {
name = reaction?["name"] as? String
}
@@ -45,6 +45,28 @@ public struct Reaction {
self.name = name
users[user] = user
}
internal init?(name: String?, users: [String: String]) {
self.name = name
self.users = users
}
static func reactionsFromArray(array: [[String: AnyObject]]) -> [String: Reaction] {
var reactions = [String: Reaction]()
var userDictionary = [String: String]()
for reaction in array {
if let users = reaction["users"] as? [String] {
for user in users {
userDictionary[user] = user
}
}
if let name = reaction["name"] as? String {
reactions[name] = Reaction(name: name, users: userDictionary)
}
}
return reactions
}
}
extension Reaction: Equatable {}
@@ -55,22 +77,25 @@ public func ==(lhs: Reaction, rhs: Reaction) -> Bool {
// MARK: - Comment
public struct Comment {
let id: String?
let user: String?
internal(set) public var timestamp: String?
public let id: String?
public let user: String?
internal(set) public var created: Int?
internal(set) public var comment: String?
internal(set) public var starred: Bool?
internal(set) public var stars: Int?
internal(set) public var reactions = [String: Reaction]()
internal init?(comment:Dictionary<String, AnyObject>?) {
internal init?(comment:[String: AnyObject]?) {
id = comment?["id"] as? String
timestamp = comment?["timestamp"] as? String
created = comment?["created"] as? Int
user = comment?["user"] as? String
starred = comment?["is_starred"] as? Bool
stars = comment?["num_stars"] as? Int
self.comment = comment?["comment"] as? String
}
internal init?(id: String?) {
self.id = id
self.comment = nil
self.timestamp = nil
self.user = nil
}
}
@@ -83,20 +108,34 @@ public func ==(lhs: Comment, rhs: Comment) -> Bool {
// MARK: - Item
public struct Item {
let type: String?
let ts: String?
let channel: String?
let message: Message?
let file: File?
let comment: Comment?
public let type: String?
public let ts: String?
public let channel: String?
public let message: Message?
public let file: File?
public let comment: Comment?
public let fileCommentID: String?
internal init?(item:Dictionary<String, AnyObject>?) {
internal init?(item:[String: AnyObject]?) {
type = item?["type"] as? String
ts = item?["ts"] as? String
channel = item?["channel"] as? String
message = Message(message: item?["message"] as? Dictionary<String, AnyObject>)
file = File(file: item?["file"] as? Dictionary<String, AnyObject>)
comment = Comment(comment: item?["comment"] as? Dictionary<String, AnyObject>)
message = Message(message: item?["message"] as? [String: AnyObject])
// Comment and File can come across as Strings or Dictionaries
if (Comment(comment: item?["comment"] as? [String: AnyObject])?.id == nil) {
comment = Comment(id: item?["comment"] as? String)
} else {
comment = Comment(comment: item?["comment"] as? [String: AnyObject])
}
if (File(file: item?["file"] as? [String: AnyObject])?.id == nil) {
file = File(id: item?["file"] as? String)
} else {
file = File(file: item?["file"] as? [String: AnyObject])
}
fileCommentID = item?["file_comment"] as? String
}
}
@@ -108,13 +147,31 @@ public func ==(lhs: Item, rhs: Item) -> Bool {
// MARK: - Topic
public struct Topic {
let value: String?
let creator: String?
let lastSet: String?
public let value: String?
public let creator: String?
public let lastSet: Int?
internal init?(topic: Dictionary<String, AnyObject>?) {
internal init?(topic: [String: AnyObject]?) {
value = topic?["value"] as? String
creator = topic?["creator"] as? String
lastSet = topic?["last_set"] as? String
lastSet = topic?["last_set"] as? Int
}
}
// MARK: - Do Not Disturb Status
public struct DoNotDisturbStatus {
internal(set) public var enabled: Bool?
internal(set) public var nextDoNotDisturbStart: Int?
internal(set) public var nextDoNotDisturbEnd: Int?
internal(set) public var snoozeEnabled: Bool?
internal(set) public var snoozeEndtime: Int?
internal init?(status: [String: AnyObject]?) {
enabled = status?["dnd_enabled"] as? Bool
nextDoNotDisturbStart = status?["next_dnd_start_ts"] as? Int
nextDoNotDisturbEnd = status?["next_dnd_end_ts"] as? Int
snoozeEnabled = status?["snooze_enabled"] as? Bool
snoozeEndtime = status?["snooze_endtime"] as? Int
}
}
+12 -9
View File
@@ -1,7 +1,7 @@
//
// User.swift
//
// Copyright © 2015 Peter Zignego. All rights reserved.
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
public struct User {
public struct Profile {
public struct Profile {
internal(set) public var firstName: String?
internal(set) public var lastName: String?
internal(set) public var realName: String?
@@ -36,7 +36,7 @@ public struct User {
internal(set) public var image72: String?
internal(set) public var image192: String?
internal init?(profile: Dictionary<String, AnyObject>?) {
internal init?(profile: [String: AnyObject]?) {
firstName = profile?["first_name"] as? String
lastName = profile?["last_name"] as? String
realName = profile?["real_name"] as? String
@@ -51,13 +51,14 @@ public struct User {
}
}
let id: String?
public let id: String?
internal(set) public var name: String?
internal(set) public var deleted: Bool?
internal(set) public var profile: Profile?
internal(set) public var doNotDisturbStatus: DoNotDisturbStatus?
internal(set) public var presence: String?
internal(set) public var color: String?
let isBot: Bool?
public let isBot: Bool?
internal(set) public var isAdmin: Bool?
internal(set) public var isOwner: Bool?
internal(set) public var isPrimaryOwner: Bool?
@@ -69,13 +70,15 @@ public struct User {
internal(set) public var timeZone: String?
internal(set) public var timeZoneLabel: String?
internal(set) public var timeZoneOffSet: Int?
internal(set) public var preferences: Dictionary<String, AnyObject>?
internal(set) public var preferences: [String: AnyObject]?
// Client use
internal(set) public var userGroups: [String: String]?
internal init?(user: Dictionary<String, AnyObject>?) {
internal init?(user: [String: AnyObject]?) {
id = user?["id"] as? String
name = user?["name"] as? String
deleted = user?["deleted"] as? Bool
profile = Profile(profile: user?["profile"] as? Dictionary<String, AnyObject>)
profile = Profile(profile: user?["profile"] as? [String: AnyObject])
color = user?["color"] as? String
isAdmin = user?["is_admin"] as? Bool
isOwner = user?["is_owner"] as? Bool
@@ -90,7 +93,7 @@ public struct User {
timeZone = user?["tz"] as? String
timeZoneLabel = user?["tz_label"] as? String
timeZoneOffSet = user?["tz_offset"] as? Int
preferences = user?["prefs"] as? Dictionary<String, AnyObject>
preferences = user?["prefs"] as? [String: AnyObject]
}
internal init?(id: String?) {
+68
View File
@@ -0,0 +1,68 @@
//
// UserGroup.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
public struct UserGroup {
public let id: String?
internal(set) public var teamID: String?
public let isUserGroup: Bool?
internal(set) public var name: String?
internal(set) public var description: String?
internal(set) public var handle: String?
internal(set) public var isExternal: Bool?
public let dateCreated: Int?
internal(set) public var dateUpdated: Int?
internal(set) public var dateDeleted: Int?
internal(set) public var autoType: String?
public let createdBy: String?
internal(set) public var updatedBy: String?
internal(set) public var deletedBy: String?
internal(set) public var preferences: [String: AnyObject]?
internal(set) public var users: [String]?
internal(set) public var userCount: Int?
internal init?(userGroup: [String: AnyObject]?) {
id = userGroup?["id"] as? String
teamID = userGroup?["team_id"] as? String
isUserGroup = userGroup?["is_usergroup"] as? Bool
name = userGroup?["name"] as? String
description = userGroup?["description"] as? String
handle = userGroup?["handle"] as? String
isExternal = userGroup?["is_external"] as? Bool
dateCreated = userGroup?["date_create"] as? Int
dateUpdated = userGroup?["date_update"] as? Int
dateDeleted = userGroup?["date_delete"] as? Int
autoType = userGroup?["auto_type"] as? String
createdBy = userGroup?["created_by"] as? String
updatedBy = userGroup?["updated_by"] as? String
deletedBy = userGroup?["deleted_by"] as? String
preferences = userGroup?["prefs"] as? [String: AnyObject]
users = userGroup?["users"] as? [String]
if let count = userGroup?["user_count"] as? String {
userCount = Int(count)
}
}
}