Compare commits

..

32 Commits

Author SHA1 Message Date
Peter Zignego 4230d7841c Merge pull request #32 from pvzig/feature/carthage-support
Feature/carthage support
2016-05-15 16:22:18 -04:00
Peter Zignego 8995a54d15 Fix project file and schemes after merge 2016-05-15 16:16:26 -04:00
Peter Zignego ba43a123ea Merge branch 'master' into feature/carthage-support
# Conflicts:
#	SlackKit.podspec
#	SlackKit.xcodeproj/project.pbxproj
#	SlackKit.xcodeproj/xcshareddata/xcschemes/SlackKit.xcscheme
2016-05-15 15:57:27 -04:00
Peter Zignego d00419dc18 Framework build details 2016-05-15 15:41:42 -04:00
Peter Zignego 15f3a30ba9 Framework build details 2016-05-15 15:39:47 -04:00
Peter Zignego befa53e3a9 Update ignore 2016-05-15 15:28:43 -04:00
Peter Zignego 35dfa840e8 Revert "Use submodule to handle core dependency"
This reverts commit edf56e1678.
2016-05-15 15:25:36 -04:00
Peter Zignego edf56e1678 Use submodule to handle core dependency 2016-05-15 15:21:47 -04:00
Peter Zignego 3eab323564 Ignore Cartfile.resolved 2016-05-15 15:04:34 -04:00
Peter Zignego 0b2ee1d10e Clean up project file 2016-05-15 14:51:15 -04:00
Peter Zignego 13335b5de1 Add additional shared schemes 2016-05-15 14:09:21 -04:00
Peter Zignego c8d8e18db6 Move AttachmentColor enum 2016-05-14 20:11:14 -04:00
Peter Zignego c11321c116 File name comment fixes 2016-05-14 20:08:54 -04:00
Michal Laskowski 0041a118a7 Fix circular dependencies (#30)
* Remove EventDispatcher, EventHandler classes; extend Client

* Make delegates weak

* Remove unneded 'if let delegate = '

* Move files around
2016-05-14 19:51:08 -04:00
Michal Laskowski 6cb5280cf5 Add tvOS target to podspec 2016-05-11 10:12:15 -05:00
Peter Zignego 9cad043957 Add shared scheme 2016-05-06 15:02:39 -04:00
Peter Zignego fa15ed8751 Merge pull request #28 from hamin/add-larger-thumbs-to-file
Adding support for larger size File thumbs
2016-05-04 12:02:42 -04:00
Haris Amin 0c9c146d58 Adding support for larger size File thumbs 2016-05-04 01:58:43 -04:00
Peter Zignego 109a20fac2 Readme update 2016-04-27 23:18:19 -04:00
Peter Zignego a6cf1e3cb6 Revert "Delete and add Cartfile.resolved to ignore"
This reverts commit d3c16bed5f.
2016-04-27 23:17:41 -04:00
Peter Zignego d3c16bed5f Delete and add Cartfile.resolved to ignore 2016-04-27 23:07:55 -04:00
Peter Zignego 797d95ab75 Update readme 2016-04-27 22:54:30 -04:00
Nate Stedman efb7bc9458 Use Carthage for resolving dependencies. 2016-04-27 22:34:28 -04:00
Peter Zignego 79e59f23fb Bump version number 2016-04-27 19:33:48 -04:00
Peter Zignego 01e199659e Update readme 2016-04-27 19:30:48 -04:00
Peter Zignego 851b2f5e14 Merge pull request #27 from pvzig/1.0.2
v1.0.2
2016-04-27 19:26:26 -04:00
Peter Zignego c506512800 Add files.info 2016-04-27 19:18:12 -04:00
Peter Zignego 20fa05605b Merge branch 'master' of https://github.com/pvzig/SlackRTMKit 2016-04-27 17:44:55 -04:00
Peter Zignego 30baf1f76c Add clientConnectionFailed delegate 2016-04-27 17:44:51 -04:00
Peter Zignego 1c3f01f861 Fix typo in example 2016-04-27 17:39:23 -04:00
Peter Zignego 47dc9b3d9f Merge pull request #25 from muratayusuke/feature/make_token_public
Make token public
2016-04-25 10:28:45 -04:00
muratayusuke b9e828ef3d Make token public 2016-04-24 18:44:40 +09:00
45 changed files with 2734 additions and 853 deletions
+5 -4
View File
@@ -16,9 +16,10 @@ DerivedData
*.hmap
*.ipa
*.xcuserstate
.build
# SwiftPM
Packages/
*.xcodeproj/
.build
# CocoaPods
#
@@ -27,10 +28,10 @@ Packages/
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
Pods/
SlackKit.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Checkouts
Carthage/Build
-1
View File
@@ -1 +0,0 @@
DEVELOPMENT-SNAPSHOT-2016-05-09-a
+1
View File
@@ -0,0 +1 @@
github "daltoniam/Starscream" ~> 1.0
+1
View File
@@ -0,0 +1 @@
github "daltoniam/Starscream" "1.1.3"
-8
View File
@@ -1,8 +0,0 @@
import PackageDescription
let package = Package(
name: "leaderboard",
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0, minor: 0),
]
)
-9
View File
@@ -1,9 +0,0 @@
import PackageDescription
let package = Package(
name: "robot-or-not-bot",
targets: [],
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0, minor: 0),
]
)
@@ -1,139 +0,0 @@
//
// main.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 SlackKit
class RobotOrNotBot: MessageEventsDelegate {
let verdicts: [String:Bool] = [
"Mr. Roboto" : false,
"Service Kiosks": false,
"Darth Vader": false,
"K-9": true,
"Emotions": false,
"Self-Driving Cars": false,
"Telepresence Robots": false,
"Roomba": true,
"Assembly-Line Robot": false,
"ASIMO": false,
"KITT": false,
"USS Enterprise": false,
"Transformers": true,
"Jaegers": false,
"The Major": false,
"Siri": false,
"The Terminator": true,
"Commander Data": false,
"Marvin the Paranoid Android": true,
"Pinocchio": false,
"Droids": true,
"Hitchbot": false,
"Mars Rovers": false,
"Space Probes": false,
"Sasquatch": false,
"Toaster": false,
"Toaster Oven": false,
"Cylons": false,
"V'ger": true,
"Ilia Robot": false,
"The TARDIS": false,
"Johnny 5": true,
"Twiki": true,
"Dr. Theopolis": false,
"robots.txt": false,
"Lobot": false,
"Vicki": true,
"GlaDOS": false,
"Turrets": true,
"Wheatley": true,
"Herbie the Love Bug": false,
"Iron Man": false,
"Ultron": false,
"The Vision": false,
"Clockwork Droids": false,
"Podcasts": false,
"Cars": false,
"Swimming Pool Cleaners": false,
"Burritos": false,
"Prince Robot IV": false,
"Daleks": false,
"Cybermen": false,
"The Internet of Things": false,
"Nanobots": true,
"Two Intermeshed Gears": false,
"Crow T. Robot": true,
"Tom Servo": true,
"Thomas and Friends": false,
"Replicants": false,
"Chatbots": false,
"Agents": false,
"Lego Simulated Worm Toy": true,
"Ghosts": false,
"Exos": true,
"Rasputin": false,
"Tamagotchi": false,
"T-1000": true,
"The Tin Woodman": false,
"Mic N. The Robot": true,
"Robot Or Not Bot": false
]
let client: SlackClient
init(token: String) {
client = SlackClient(apiToken: token)
client.messageEventsDelegate = self
}
// MARK: MessageEventsDelegate
func messageReceived(message: Message) {
if let id = client.authenticatedUser?.id {
if message.text?.contains(query: id) == true {
handleMessage(message: message)
}
}
}
func messageSent(message: Message){}
func messageChanged(message: Message){}
func messageDeleted(message: Message?){}
private func handleMessage(message: Message) {
if let text = message.text?.lowercased(), channel = message.channel {
for (robot, verdict) in verdicts {
let lowerbot = robot.lowercased()
if text.contains(query: lowerbot) {
if verdict == true {
client.webAPI.addReaction(name: "robot_face", timestamp: message.ts, channel: channel, success: nil, failure: nil)
} else {
client.webAPI.addReaction(name: "no_entry_sign", timestamp: message.ts, channel: channel, success: nil, failure: nil)
}
return
}
}
client.webAPI.addReaction(name: "question", timestamp: message.ts, channel: channel, success: nil, failure: nil)
}
}
}
let slackbot = RobotOrNotBot(token: "xoxb-SLACK_API_TOKEN")
slackbot.client.connect()
+44
View File
@@ -0,0 +1,44 @@
//
// AppDelegate.swift
// OSX-Sample
//
// 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 Cocoa
import SlackKit
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
let leaderboard = Leaderboard(token: "SLACK_AUTH_TOKEN")
func applicationDidFinishLaunching(aNotification: NSNotification) {
leaderboard.client.connect()
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
@@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
+680
View File
@@ -0,0 +1,680 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6233" systemVersion="14A329f" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6233"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModuleProvider="target">
<connections>
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="OSX-Sample" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="OSX-Sample" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About OSX-Sample" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide OSX-Sample" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit OSX-Sample" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="-1" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="-1" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="-1" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="-1" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" id="KaW-ft-85H">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="revertDocumentToSaved:" target="-1" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="-1" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
<items>
<menuItem title="Font" id="Gi5-1S-RQB">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
<connections>
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
<connections>
<action selector="underline:" target="-1" id="FYS-2b-JAY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
<menuItem title="Kern" id="jBQ-r6-VK2">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
<items>
<menuItem title="Use Default" id="GUa-eO-cwY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="6dk-9l-Ckg"/>
</connections>
</menuItem>
<menuItem title="Use None" id="cDB-IK-hbR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="U8a-gz-Maa"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="46P-cB-AYj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="hr7-Nz-8ro"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="ogc-rX-tC1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="8i4-f9-FKE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="o6e-r0-MWq">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
<items>
<menuItem title="Use Default" id="agt-UL-0e3">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="7uR-wd-Dx6"/>
</connections>
</menuItem>
<menuItem title="Use None" id="J7y-lM-qPV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="iX2-gA-Ilz"/>
</connections>
</menuItem>
<menuItem title="Use All" id="xQD-1f-W4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="KcB-kA-TuK"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="OaQ-X3-Vso">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
<items>
<menuItem title="Use Default" id="3Om-Ey-2VK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="0vZ-95-Ywn"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="Rqc-34-cIF">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="3qV-fo-wpU"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="I0S-gh-46l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="Q6W-4W-IGz"/>
</connections>
</menuItem>
<menuItem title="Raise" id="2h7-ER-AoG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="4sk-31-7Q9"/>
</connections>
</menuItem>
<menuItem title="Lower" id="1tx-W0-xDw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="OF1-bc-KW4"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="mSX-Xz-DV3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="GJO-xA-L4q"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="JfD-CL-leO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="Fal-I4-PZk">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="d9c-me-L2H">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
<connections>
<action selector="alignLeft:" target="-1" id="zUv-R1-uAa"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
<connections>
<action selector="alignCenter:" target="-1" id="spX-mk-kcS"/>
</connections>
</menuItem>
<menuItem title="Justify" id="J5U-5w-g23">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="ljL-7U-jND"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
<connections>
<action selector="alignRight:" target="-1" id="r48-bG-YeY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
<menuItem title="Writing Direction" id="H1b-Si-o9J">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
<items>
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="YGs-j5-SAR">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="qtV-5e-UBP"/>
</connections>
</menuItem>
<menuItem id="Lbh-J2-qVU">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="S0X-9S-QSf"/>
</connections>
</menuItem>
<menuItem id="jFq-tB-4Kx">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="5fk-qB-AqJ"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="Nop-cj-93Q">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="lPI-Se-ZHp"/>
</connections>
</menuItem>
<menuItem id="BgM-ve-c93">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="caW-Bv-w94"/>
</connections>
</menuItem>
<menuItem id="RB4-Sm-HuC">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="EXD-6r-ZUu"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
<menuItem title="Show Ruler" id="vLm-3I-IUL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="FOx-HJ-KwY"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="71i-fW-3W2"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="cSh-wd-qM2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="runToolbarCustomizationPalette:" target="-1" id="pQI-g3-MTW"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="OSX-Sample Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<window title="OSX-Sample" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1177"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Launch Software LLC. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
@@ -1,5 +1,6 @@
//
// main.swift
// Leaderboard.swift
// OSX-Sample
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
@@ -21,21 +22,21 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import String
import SlackKit
import Foundation
class Leaderboard: MessageEventsDelegate {
var leaderboard: [String: Int] = [String: Int]()
let atSet = CharacterSet(characters: ["@"])
let client: SlackClient
let atSet = NSCharacterSet(charactersInString: "@")
let client: Client
init(token: String) {
client = SlackClient(apiToken: token)
client = Client(apiToken: token)
client.messageEventsDelegate = self
}
enum Command: String {
case Leaderboard = "leaderboard"
}
@@ -47,7 +48,7 @@ class Leaderboard: MessageEventsDelegate {
// MARK: MessageEventsDelegate
func messageReceived(message: Message) {
listen(message: message)
listen(message)
}
func messageSent(message: Message){}
@@ -57,31 +58,31 @@ class Leaderboard: MessageEventsDelegate {
// MARK: Leaderboard Internal Logic
private func listen(message: Message) {
if let id = client.authenticatedUser?.id, text = message.text {
if text.lowercased().contains(query: Command.Leaderboard.rawValue) && text.contains(query: id) {
handleCommand(command: .Leaderboard, channel: message.channel)
if text.lowercaseString.containsString(Command.Leaderboard.rawValue) && text.containsString(id) == true {
handleCommand(.Leaderboard, channel: message.channel)
}
}
if message.text?.contains(query: Trigger.PlusPlus.rawValue) == true {
handleMessageWithTrigger(message: message, trigger: .PlusPlus)
if message.text?.containsString(Trigger.PlusPlus.rawValue) == true {
handleMessageWithTrigger(message, trigger: .PlusPlus)
}
if message.text?.contains(query: Trigger.MinusMinus.rawValue) == true {
handleMessageWithTrigger(message: message, trigger: .MinusMinus)
if message.text?.containsString(Trigger.MinusMinus.rawValue) == true {
handleMessageWithTrigger(message, trigger: .MinusMinus)
}
}
private func handleMessageWithTrigger(message: Message, trigger: Trigger) {
if let text = message.text,
start = text.index(of: "@"),
end = text.index(of: trigger.rawValue) {
let string = String(text.characters[start...end].dropLast().dropFirst())
let users = client.users.values.filter{$0.id == self.userID(string: string)}
end = text.rangeOfString(trigger.rawValue)?.startIndex.predecessor(),
start = text.rangeOfCharacterFromSet(atSet, options: .BackwardsSearch, range: text.startIndex..<end)?.startIndex {
let string = text.substringWithRange(start...end)
let users = client.users.values.filter{$0.id == self.userID(string)}
if users.count > 0 {
let idString = userID(string: string)
initalizationForValue(dictionary: &leaderboard, value: idString)
scoringForValue(dictionary: &leaderboard, value: idString, trigger: trigger)
let idString = userID(string)
initalizationForValue(&leaderboard, value: idString)
scoringForValue(&leaderboard, value: idString, trigger: trigger)
} else {
initalizationForValue(dictionary: &leaderboard, value: string)
scoringForValue(dictionary: &leaderboard, value: string, trigger: trigger)
initalizationForValue(&leaderboard, value: string)
scoringForValue(&leaderboard, value: string, trigger: trigger)
}
}
}
@@ -90,7 +91,7 @@ class Leaderboard: MessageEventsDelegate {
switch command {
case .Leaderboard:
if let id = channel {
client.webAPI.sendMessage(channel:id, text: "Leaderboard", linkNames: true, attachments: [constructLeaderboardAttachment()], success: {(response) in
client.webAPI.sendMessage(id, text: "", linkNames: true, attachments: [constructLeaderboardAttachment()], success: {(response) in
}, failure: { (error) in
print("Leaderboard failed to post due to error:\(error)")
@@ -99,13 +100,13 @@ class Leaderboard: MessageEventsDelegate {
}
}
private func initalizationForValue( dictionary: inout [String: Int], value: String) {
private func initalizationForValue(inout dictionary: [String: Int], value: String) {
if dictionary[value] == nil {
dictionary[value] = 0
}
}
private func scoringForValue( dictionary: inout [String: Int], value: String, trigger: Trigger) {
private func scoringForValue(inout dictionary: [String: Int], value: String, trigger: Trigger) {
switch trigger {
case .PlusPlus:
dictionary[value]?+=1
@@ -116,21 +117,21 @@ class Leaderboard: MessageEventsDelegate {
// MARK: Leaderboard Interface
private func constructLeaderboardAttachment() -> Attachment? {
let 💯 = AttachmentField(title: "💯", value: swapIDsForNames(string: topItems(dictionary: &leaderboard)), short: true)
let 💩 = AttachmentField(title: "💩", value: swapIDsForNames(string: bottomItems(dictionary: &leaderboard)), short: true)
let 💯 = AttachmentField(title: "💯", value: swapIDsForNames(topItems(&leaderboard)), short: true)
let 💩 = AttachmentField(title: "💩", value: swapIDsForNames(bottomItems(&leaderboard)), short: true)
return Attachment(fallback: "Leaderboard", title: "Leaderboard", colorHex: AttachmentColor.Good.rawValue, text: "", fields: [💯, 💩])
}
private func topItems(dictionary: inout [String: Int]) -> String {
let sortedKeys = dictionary.keys.sorted(isOrderedBefore: ({dictionary[$0] > dictionary[$1]})).filter({dictionary[$0] > 0})
let sortedValues = dictionary.values.sorted(isOrderedBefore: {$0 > $1}).filter({$0 > 0})
return leaderboardString(keys: sortedKeys, values: sortedValues)
private func topItems(inout dictionary: [String: Int]) -> String {
let sortedKeys = Array(dictionary.keys).sort({dictionary[$0] > dictionary[$1]}).filter({dictionary[$0] > 0})
let sortedValues = Array(dictionary.values).sort({$0 > $1}).filter({$0 > 0})
return leaderboardString(sortedKeys, values: sortedValues)
}
private func bottomItems( dictionary: inout [String: Int]) -> String {
let sortedKeys = dictionary.keys.sorted(isOrderedBefore: ({dictionary[$0] < dictionary[$1]})).filter({dictionary[$0] < 0})
let sortedValues = dictionary.values.sorted(isOrderedBefore: {$0 < $1}).filter({$0 < 0})
return leaderboardString(keys: sortedKeys, values: sortedValues)
private func bottomItems(inout dictionary: [String: Int]) -> String {
let sortedKeys = Array(dictionary.keys).sort({dictionary[$0] < dictionary[$1]}).filter({dictionary[$0] < 0})
let sortedValues = Array(dictionary.values).sort({$0 < $1}).filter({$0 < 0})
return leaderboardString(sortedKeys, values: sortedValues)
}
private func leaderboardString(keys: [String], values: [Int]) -> String {
@@ -146,22 +147,14 @@ class Leaderboard: MessageEventsDelegate {
var returnString = string
for key in client.users.keys {
if let name = client.users[key]?.name {
if returnString.contains(query: key) {
returnString.replace(string: key, with: "@"+name)
}
returnString = returnString.stringByReplacingOccurrencesOfString(key, withString: "@"+name, options: NSStringCompareOptions.LiteralSearch, range: returnString.startIndex..<returnString.endIndex)
}
}
return returnString
}
private func userID(string: String) -> String {
let alphanumericSet = CharacterSet(characters:
["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
"0","1","2","3","4","5","6","7","8","9"])
return string.trim(alphanumericSet.inverted)
return string.stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet)
}
}
let leaderboard = Leaderboard(token: "xoxb-SLACK_API_TOKEN")
leaderboard.client.connect()
}
+3 -5
View File
@@ -27,9 +27,7 @@ let package = Package(
name: "SlackKit",
targets: [],
dependencies: [
.Package(url: "https://github.com/Zewo/WebSocketClient", majorVersion: 0, minor: 2),
.Package(url: "https://github.com/open-swift/C7.git", majorVersion: 0, minor: 8),
.Package(url: "https://github.com/czechboy0/Jay.git", majorVersion: 0, minor: 6),
],
exclude: ["Examples"]
.Package(url: "https://github.com/pvzig/Starscream.git",
majorVersion: 1),
]
)
+15
View File
@@ -0,0 +1,15 @@
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
target 'SlackKit' do
pod 'Starscream'
end
target 'SlackKit_iOS' do
pod 'Starscream'
end
target 'SlackKit_tvOS' do
pod 'Starscream'
end
+12
View File
@@ -0,0 +1,12 @@
PODS:
- Starscream (1.1.3)
DEPENDENCIES:
- Starscream
SPEC CHECKSUMS:
Starscream: d662732354b40dd19ed1ece3e3c44c80b536b83c
PODFILE CHECKSUM: d22778f772dbbded8b17fbebf5fa1c879d785aee
COCOAPODS: 1.0.0
+46 -24
View File
@@ -1,11 +1,33 @@
![SlackKit](https://cloud.githubusercontent.com/assets/8311605/10260893/5ec60f96-694e-11e5-91fd-da6845942201.png)
##Alpha Linux Slack Client Library
##iOS/OS X Slack Client Library
###Description
This is a Slack client library for Linux written in Swift. It's intended to expose all of the functionality of Slack's [Real Time Messaging API](https://api.slack.com/rtm) as well as the [web APIs](https://api.slack.com/web) that are accessible by [bot users](https://api.slack.com/bot-users).
This is a Slack client library for OS X, iOS, and tvOS written in Swift. It's intended to expose all of the functionality of Slack's [Real Time Messaging API](https://api.slack.com/rtm) as well as the [web APIs](https://api.slack.com/web) that are accessible by [bot users](https://api.slack.com/bot-users).
###Disclaimer: The linux version of SlackKit is a pre-release alpha. Feel free to report issues you come across.
####Building the SlackKit Framework
To build the SlackKit project directly, first build the dependencies using Carthage or CocoaPods. To use the framework in your application, install it in one of the following ways:
###Installation
####CocoaPods
Add the pod to your podfile:
```
pod 'SlackKit'
```
and run
```
pod install
```
####Carthage
Add SlackKit to your Cartfile:
```
github “pvzig/SlackKit” ~> 1.0
```
and run
```
carthage update
```
Drag the built SlackKit.framework into your Xcode project.
####Swift Package Manager
Add SlackKit to your Package.swift
@@ -15,37 +37,18 @@ import PackageDescription
let package = Package(
dependencies: [
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 0, minor: 0)
.Package(url: "https://github.com/pvzig/SlackKit.git", majorVersion: 1)
]
)
```
####Development
1. Install Homebrew: `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
2. Install `swiftenv`: `brew install kylef/formulae/swiftenv`
3. Configure your shell: `echo 'if which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.bash_profile`
4. Download and install the latest Zewo compatible snapshot:
```
swiftenv install DEVELOPMENT-SNAPSHOT-2016-05-03-a
swiftenv local DEVELOPMENT-SNAPSHOT-2016-05-03-a
```
5. Install and Link OpenSSL: `brew install openssl`, `brew link openssl --force`
To build an application that uses SlackKit in Xcode, simply use SwiftPM. (For the 05-03 snapshot you must run `swift build` before generating an Xcode project:
```
swift build
swift build -Xlinker -L$(pwd)/.build/debug/ -Xswiftc -I/usr/local/include -Xlinker -L/usr/local/lib -X
```
Run `swift-build` on your applications main directory.
To use the library in your project import it:
```
import SlackKit
```
####Deployment
Deploy your application to Heroku using [this buildpack](https://github.com/pvzig/heroku-buildpack-swift). For more detailed instructions please see [this post](https://medium.com/@pvzig/building-slack-bots-in-swift-b99e243e444c).
###Usage
To use SlackKit you'll need a bearer token which identifies a single user. You can generate a [full access token or create one using OAuth 2](https://api.slack.com/web).
@@ -59,6 +62,11 @@ If you want to receive messages from the Slack RTM API, connect to it.
client.connect()
```
You can also set options for a ping/pong interval, timeout interval, and automatic reconnection:
```swift
client.connect(pingInterval: 2, timeout: 10, reconnect: false)
```
Once connected, the client will begin to consume any messages sent by the Slack RTM API.
####Web API Methods
@@ -80,6 +88,7 @@ SlackKit currently supports the a subset of the Slack Web APIs that are availabl
- files.comments.edit
- files.comments.delete
- files.delete
- files.info
- files.upload
- groups.close
- groups.history
@@ -137,6 +146,7 @@ There are a number of delegates that you can set to receive callbacks for certai
#####SlackEventsDelegate
```swift
func clientConnectionFailed(error: SlackError)
func clientConnected()
func clientDisconnected()
func preferenceChanged(preference: String, value: AnyObject)
@@ -223,6 +233,18 @@ func subteamSelfAdded(subteamID: String)
func subteamSelfRemoved(subteamID: String)
```
###Examples
####Leaderboard
Included in the OSX-Sample is an example application of a bot you might make using SlackKit. Its a basic leaderboard scoring bot, in the spirit of [PlusPlus](https://plusplus.chat).
To configure it, enter your bots API token in `AppDelegate.swift` for the Leaderboard bot:
```swift
let learderboard = Leaderboard(token: "SLACK_AUTH_TOKEN")
```
It adds a point for every `@thing++`, subtracts a point for every `@thing--`, and shows a leaderboard when asked `@botname leaderboard`.
###Get In Touch
[@pvzig](https://twitter.com/pvzig)
+18
View File
@@ -0,0 +1,18 @@
Pod::Spec.new do |s|
s.name = "SlackKit"
s.version = "1.0.3"
s.summary = "a Slack client library for iOS and OS X written in Swift"
s.homepage = "https://github.com/pvzig/SlackKit"
s.license = 'MIT'
s.author = { "Peter Zignego" => "peter@launchsoft.co" }
s.source = { :git => "https://github.com/pvzig/SlackKit.git", :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/pvzig'
s.ios.deployment_target = '8.0'
s.osx.deployment_target = '10.10'
s.tvos.deployment_target = '9.0'
s.requires_arc = true
s.source_files = 'SlackKit/Sources/*.swift'
s.frameworks = 'Foundation'
s.dependency 'Starscream', '~> 1.1.3'
end
+826
View File
@@ -0,0 +1,826 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
2601D61B1C7646B80012BF22 /* SlackWebAPIErrorDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2601D61A1C7646B80012BF22 /* SlackWebAPIErrorDispatcher.swift */; };
2601D6271C7688610012BF22 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2601D6261C7688610012BF22 /* AppDelegate.swift */; };
2601D6291C7688610012BF22 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2601D6281C7688610012BF22 /* Assets.xcassets */; };
2601D62C1C7688610012BF22 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2601D62A1C7688610012BF22 /* MainMenu.xib */; };
260EC2331C4DC61D0093B253 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2301C4DC61D0093B253 /* Extensions.swift */; };
260EC2341C4DC61D0093B253 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2311C4DC61D0093B253 /* NetworkInterface.swift */; };
260EC2351C4DC61D0093B253 /* SlackWebAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */; };
263993901CE90C87004A6E93 /* SlackKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2661A6A41BBF62FF0026F67B /* SlackKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
263993971CE90EE0004A6E93 /* Client+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16C98791CE7D3DD00692776 /* Client+Utilities.swift */; };
263993981CE90EE0004A6E93 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1881C398E3C00BF7225 /* Channel.swift */; };
263993991CE90EE0004A6E93 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1921C398E3C00BF7225 /* User.swift */; };
2639939A1CE90EE0004A6E93 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1911C398E3C00BF7225 /* Types.swift */; };
2639939B1CE90EE0004A6E93 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1891C398E3C00BF7225 /* Client.swift */; };
2639939C1CE90EE0004A6E93 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18A1C398E3C00BF7225 /* Event.swift */; };
2639939D1CE90EE0004A6E93 /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1871C398E3C00BF7225 /* Bot.swift */; };
2639939E1CE90EE0004A6E93 /* Client+EventDispatching.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */; };
2639939F1CE90EE0004A6E93 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18E1C398E3C00BF7225 /* File.swift */; };
263993A01CE90EE0004A6E93 /* SlackWebAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */; };
263993A11CE90EE0004A6E93 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DF40341C7A0FA300E19241 /* Attachment.swift */; };
263993A21CE90EE0004A6E93 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18F1C398E3C00BF7225 /* Message.swift */; };
263993A31CE90EE0004A6E93 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1901C398E3C00BF7225 /* Team.swift */; };
263993A41CE90EE0004A6E93 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2301C4DC61D0093B253 /* Extensions.swift */; };
263993A51CE90EE0004A6E93 /* UserGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1931C398E3C00BF7225 /* UserGroup.swift */; };
263993A61CE90EE0004A6E93 /* SlackWebAPIErrorDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2601D61A1C7646B80012BF22 /* SlackWebAPIErrorDispatcher.swift */; };
263993A71CE90EE0004A6E93 /* Client+EventHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */; };
263993A81CE90EE0004A6E93 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2311C4DC61D0093B253 /* NetworkInterface.swift */; };
263993A91CE90EE0004A6E93 /* EventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */; };
263993AB1CE90EE0004A6E93 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4307A07F1CC6D0910011D5DE /* Starscream.framework */; };
263993AD1CE90EE0004A6E93 /* SlackKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2661A6A41BBF62FF0026F67B /* SlackKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
263993B61CE90EED004A6E93 /* Client+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16C98791CE7D3DD00692776 /* Client+Utilities.swift */; };
263993B71CE90EED004A6E93 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1881C398E3C00BF7225 /* Channel.swift */; };
263993B81CE90EED004A6E93 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1921C398E3C00BF7225 /* User.swift */; };
263993B91CE90EED004A6E93 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1911C398E3C00BF7225 /* Types.swift */; };
263993BA1CE90EED004A6E93 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1891C398E3C00BF7225 /* Client.swift */; };
263993BB1CE90EED004A6E93 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18A1C398E3C00BF7225 /* Event.swift */; };
263993BC1CE90EED004A6E93 /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1871C398E3C00BF7225 /* Bot.swift */; };
263993BD1CE90EED004A6E93 /* Client+EventDispatching.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */; };
263993BE1CE90EED004A6E93 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18E1C398E3C00BF7225 /* File.swift */; };
263993BF1CE90EED004A6E93 /* SlackWebAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */; };
263993C01CE90EED004A6E93 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DF40341C7A0FA300E19241 /* Attachment.swift */; };
263993C11CE90EED004A6E93 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18F1C398E3C00BF7225 /* Message.swift */; };
263993C21CE90EED004A6E93 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1901C398E3C00BF7225 /* Team.swift */; };
263993C31CE90EED004A6E93 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2301C4DC61D0093B253 /* Extensions.swift */; };
263993C41CE90EED004A6E93 /* UserGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1931C398E3C00BF7225 /* UserGroup.swift */; };
263993C51CE90EED004A6E93 /* SlackWebAPIErrorDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2601D61A1C7646B80012BF22 /* SlackWebAPIErrorDispatcher.swift */; };
263993C61CE90EED004A6E93 /* Client+EventHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */; };
263993C71CE90EED004A6E93 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260EC2311C4DC61D0093B253 /* NetworkInterface.swift */; };
263993C81CE90EED004A6E93 /* EventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */; };
263993CA1CE90EED004A6E93 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4307A07F1CC6D0910011D5DE /* Starscream.framework */; };
263993CC1CE90EED004A6E93 /* SlackKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2661A6A41BBF62FF0026F67B /* SlackKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
26BBA1941C398E3C00BF7225 /* Bot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1871C398E3C00BF7225 /* Bot.swift */; };
26BBA1951C398E3C00BF7225 /* Channel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1881C398E3C00BF7225 /* Channel.swift */; };
26BBA1961C398E3C00BF7225 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1891C398E3C00BF7225 /* Client.swift */; };
26BBA1971C398E3C00BF7225 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18A1C398E3C00BF7225 /* Event.swift */; };
26BBA1981C398E3C00BF7225 /* EventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */; };
26BBA19B1C398E3C00BF7225 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18E1C398E3C00BF7225 /* File.swift */; };
26BBA19C1C398E3C00BF7225 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA18F1C398E3C00BF7225 /* Message.swift */; };
26BBA19D1C398E3C00BF7225 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1901C398E3C00BF7225 /* Team.swift */; };
26BBA19E1C398E3C00BF7225 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1911C398E3C00BF7225 /* Types.swift */; };
26BBA19F1C398E3C00BF7225 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1921C398E3C00BF7225 /* User.swift */; };
26BBA1A01C398E3C00BF7225 /* UserGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BBA1931C398E3C00BF7225 /* UserGroup.swift */; };
26DF40351C7A0FA300E19241 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DF40341C7A0FA300E19241 /* Attachment.swift */; };
26F4BAC31C9DEBD1000910BA /* Leaderboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26F4BAC21C9DEBD1000910BA /* Leaderboard.swift */; };
4307A0801CC6D0910011D5DE /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4307A07F1CC6D0910011D5DE /* Starscream.framework */; };
C16C987A1CE7D3DD00692776 /* Client+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C16C98791CE7D3DD00692776 /* Client+Utilities.swift */; };
C1A85FF91CE3BCEF00756C40 /* Client+EventDispatching.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */; };
C1A85FFA1CE3BCEF00756C40 /* Client+EventHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
2601D61A1C7646B80012BF22 /* SlackWebAPIErrorDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SlackWebAPIErrorDispatcher.swift; path = Sources/SlackWebAPIErrorDispatcher.swift; sourceTree = "<group>"; };
2601D6241C7688610012BF22 /* OSX-Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "OSX-Sample.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2601D6261C7688610012BF22 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
2601D6281C7688610012BF22 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2601D62B1C7688610012BF22 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
2601D62D1C7688610012BF22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
26072A341BB48B3A00CD650C /* SlackKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SlackKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
260EC2301C4DC61D0093B253 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = Sources/Extensions.swift; sourceTree = "<group>"; };
260EC2311C4DC61D0093B253 /* NetworkInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetworkInterface.swift; path = Sources/NetworkInterface.swift; sourceTree = "<group>"; };
260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SlackWebAPI.swift; path = Sources/SlackWebAPI.swift; sourceTree = "<group>"; };
263993B21CE90EE0004A6E93 /* SlackKit_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SlackKit_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
263993D11CE90EED004A6E93 /* SlackKit_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SlackKit_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2661A6A41BBF62FF0026F67B /* SlackKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SlackKit.h; sourceTree = "<group>"; };
268E46131CE8F79D009F19CC /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-iOS.plist"; path = "Supporting Files/Info-iOS.plist"; sourceTree = "<group>"; };
268E46141CE8F79D009F19CC /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-tvOS.plist"; path = "Supporting Files/Info-tvOS.plist"; sourceTree = "<group>"; };
268E46151CE8F79D009F19CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Supporting Files/Info.plist"; sourceTree = "<group>"; };
26BBA1871C398E3C00BF7225 /* Bot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bot.swift; path = Sources/Bot.swift; sourceTree = "<group>"; };
26BBA1881C398E3C00BF7225 /* Channel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Channel.swift; path = Sources/Channel.swift; sourceTree = "<group>"; };
26BBA1891C398E3C00BF7225 /* Client.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Client.swift; path = Sources/Client.swift; sourceTree = "<group>"; };
26BBA18A1C398E3C00BF7225 /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Event.swift; path = Sources/Event.swift; sourceTree = "<group>"; };
26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EventDelegate.swift; path = Sources/EventDelegate.swift; sourceTree = "<group>"; };
26BBA18E1C398E3C00BF7225 /* File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = File.swift; path = Sources/File.swift; sourceTree = "<group>"; };
26BBA18F1C398E3C00BF7225 /* Message.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Message.swift; path = Sources/Message.swift; sourceTree = "<group>"; };
26BBA1901C398E3C00BF7225 /* Team.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Team.swift; path = Sources/Team.swift; sourceTree = "<group>"; };
26BBA1911C398E3C00BF7225 /* Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Types.swift; path = Sources/Types.swift; sourceTree = "<group>"; };
26BBA1921C398E3C00BF7225 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = User.swift; path = Sources/User.swift; sourceTree = "<group>"; };
26BBA1931C398E3C00BF7225 /* UserGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UserGroup.swift; path = Sources/UserGroup.swift; sourceTree = "<group>"; };
26DF40341C7A0FA300E19241 /* Attachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Attachment.swift; path = Sources/Attachment.swift; sourceTree = "<group>"; };
26F4BAC21C9DEBD1000910BA /* Leaderboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Leaderboard.swift; sourceTree = "<group>"; };
4307A07F1CC6D0910011D5DE /* Starscream.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Starscream.framework; path = Carthage/Build/Mac/Starscream.framework; sourceTree = "<group>"; };
C16C98791CE7D3DD00692776 /* Client+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Client+Utilities.swift"; path = "Sources/Client+Utilities.swift"; sourceTree = "<group>"; };
C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Client+EventDispatching.swift"; path = "Sources/Client+EventDispatching.swift"; sourceTree = "<group>"; };
C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Client+EventHandling.swift"; path = "Sources/Client+EventHandling.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
2601D6211C7688610012BF22 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
26072A301BB48B3A00CD650C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4307A0801CC6D0910011D5DE /* Starscream.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993AA1CE90EE0004A6E93 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
263993AB1CE90EE0004A6E93 /* Starscream.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993C91CE90EED004A6E93 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
263993CA1CE90EED004A6E93 /* Starscream.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2601D6251C7688610012BF22 /* OSX-Sample */ = {
isa = PBXGroup;
children = (
2601D6261C7688610012BF22 /* AppDelegate.swift */,
26F4BAC21C9DEBD1000910BA /* Leaderboard.swift */,
2601D6281C7688610012BF22 /* Assets.xcassets */,
2601D62A1C7688610012BF22 /* MainMenu.xib */,
2601D62D1C7688610012BF22 /* Info.plist */,
);
path = "OSX-Sample";
sourceTree = "<group>";
};
26072A2A1BB48B3A00CD650C = {
isa = PBXGroup;
children = (
2661A6811BBF60E60026F67B /* SlackKit */,
2601D6251C7688610012BF22 /* OSX-Sample */,
26072A351BB48B3A00CD650C /* Products */,
CA70A3A1A9A1A259960DFBCF /* Frameworks */,
);
sourceTree = "<group>";
};
26072A351BB48B3A00CD650C /* Products */ = {
isa = PBXGroup;
children = (
26072A341BB48B3A00CD650C /* SlackKit.framework */,
2601D6241C7688610012BF22 /* OSX-Sample.app */,
263993B21CE90EE0004A6E93 /* SlackKit_iOS.framework */,
263993D11CE90EED004A6E93 /* SlackKit_tvOS.framework */,
);
name = Products;
sourceTree = "<group>";
};
2661A6811BBF60E60026F67B /* SlackKit */ = {
isa = PBXGroup;
children = (
26DF40341C7A0FA300E19241 /* Attachment.swift */,
26BBA1871C398E3C00BF7225 /* Bot.swift */,
26BBA1881C398E3C00BF7225 /* Channel.swift */,
26BBA1891C398E3C00BF7225 /* Client.swift */,
C1A85FF81CE3BCEF00756C40 /* Client+EventHandling.swift */,
C1A85FF71CE3BCEF00756C40 /* Client+EventDispatching.swift */,
C16C98791CE7D3DD00692776 /* Client+Utilities.swift */,
26BBA18A1C398E3C00BF7225 /* Event.swift */,
26BBA18B1C398E3C00BF7225 /* EventDelegate.swift */,
260EC2301C4DC61D0093B253 /* Extensions.swift */,
26BBA18E1C398E3C00BF7225 /* File.swift */,
26BBA18F1C398E3C00BF7225 /* Message.swift */,
260EC2311C4DC61D0093B253 /* NetworkInterface.swift */,
260EC2321C4DC61D0093B253 /* SlackWebAPI.swift */,
2601D61A1C7646B80012BF22 /* SlackWebAPIErrorDispatcher.swift */,
26BBA1901C398E3C00BF7225 /* Team.swift */,
26BBA1911C398E3C00BF7225 /* Types.swift */,
26BBA1921C398E3C00BF7225 /* User.swift */,
26BBA1931C398E3C00BF7225 /* UserGroup.swift */,
268E46161CE8F7A2009F19CC /* Supporting Files */,
);
path = SlackKit;
sourceTree = "<group>";
};
268E46161CE8F7A2009F19CC /* Supporting Files */ = {
isa = PBXGroup;
children = (
2661A6A41BBF62FF0026F67B /* SlackKit.h */,
268E46151CE8F79D009F19CC /* Info.plist */,
268E46131CE8F79D009F19CC /* Info-iOS.plist */,
268E46141CE8F79D009F19CC /* Info-tvOS.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
CA70A3A1A9A1A259960DFBCF /* Frameworks */ = {
isa = PBXGroup;
children = (
4307A07F1CC6D0910011D5DE /* Starscream.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
26072A311BB48B3A00CD650C /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
263993901CE90C87004A6E93 /* SlackKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993AC1CE90EE0004A6E93 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
263993AD1CE90EE0004A6E93 /* SlackKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993CB1CE90EED004A6E93 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
263993CC1CE90EED004A6E93 /* SlackKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
2601D6231C7688610012BF22 /* OSX-Sample */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2601D62E1C7688610012BF22 /* Build configuration list for PBXNativeTarget "OSX-Sample" */;
buildPhases = (
2601D6201C7688610012BF22 /* Sources */,
2601D6211C7688610012BF22 /* Frameworks */,
2601D6221C7688610012BF22 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "OSX-Sample";
productName = "OSX-Sample";
productReference = 2601D6241C7688610012BF22 /* OSX-Sample.app */;
productType = "com.apple.product-type.application";
};
26072A331BB48B3A00CD650C /* SlackKit */ = {
isa = PBXNativeTarget;
buildConfigurationList = 26072A3C1BB48B3B00CD650C /* Build configuration list for PBXNativeTarget "SlackKit" */;
buildPhases = (
26072A2F1BB48B3A00CD650C /* Sources */,
26072A301BB48B3A00CD650C /* Frameworks */,
26072A311BB48B3A00CD650C /* Headers */,
26072A321BB48B3A00CD650C /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = SlackKit;
productName = SlackRTMKit;
productReference = 26072A341BB48B3A00CD650C /* SlackKit.framework */;
productType = "com.apple.product-type.framework";
};
263993951CE90EE0004A6E93 /* SlackKit_iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 263993AF1CE90EE0004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit_iOS" */;
buildPhases = (
263993961CE90EE0004A6E93 /* Sources */,
263993AA1CE90EE0004A6E93 /* Frameworks */,
263993AC1CE90EE0004A6E93 /* Headers */,
263993AE1CE90EE0004A6E93 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = SlackKit_iOS;
productName = SlackRTMKit;
productReference = 263993B21CE90EE0004A6E93 /* SlackKit_iOS.framework */;
productType = "com.apple.product-type.framework";
};
263993B41CE90EED004A6E93 /* SlackKit_tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 263993CE1CE90EED004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit_tvOS" */;
buildPhases = (
263993B51CE90EED004A6E93 /* Sources */,
263993C91CE90EED004A6E93 /* Frameworks */,
263993CB1CE90EED004A6E93 /* Headers */,
263993CD1CE90EED004A6E93 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = SlackKit_tvOS;
productName = SlackRTMKit;
productReference = 263993D11CE90EED004A6E93 /* SlackKit_tvOS.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
26072A2B1BB48B3A00CD650C /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0720;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Launch Software LLC";
TargetAttributes = {
2601D6231C7688610012BF22 = {
CreatedOnToolsVersion = 7.2.1;
};
26072A331BB48B3A00CD650C = {
CreatedOnToolsVersion = 7.0;
};
};
};
buildConfigurationList = 26072A2E1BB48B3A00CD650C /* Build configuration list for PBXProject "SlackKit" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 26072A2A1BB48B3A00CD650C;
productRefGroup = 26072A351BB48B3A00CD650C /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
26072A331BB48B3A00CD650C /* SlackKit */,
263993951CE90EE0004A6E93 /* SlackKit_iOS */,
263993B41CE90EED004A6E93 /* SlackKit_tvOS */,
2601D6231C7688610012BF22 /* OSX-Sample */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
2601D6221C7688610012BF22 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2601D6291C7688610012BF22 /* Assets.xcassets in Resources */,
2601D62C1C7688610012BF22 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
26072A321BB48B3A00CD650C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
263993AE1CE90EE0004A6E93 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
263993CD1CE90EED004A6E93 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
2601D6201C7688610012BF22 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2601D6271C7688610012BF22 /* AppDelegate.swift in Sources */,
26F4BAC31C9DEBD1000910BA /* Leaderboard.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
26072A2F1BB48B3A00CD650C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C16C987A1CE7D3DD00692776 /* Client+Utilities.swift in Sources */,
26BBA1951C398E3C00BF7225 /* Channel.swift in Sources */,
26BBA19F1C398E3C00BF7225 /* User.swift in Sources */,
26BBA19E1C398E3C00BF7225 /* Types.swift in Sources */,
26BBA1961C398E3C00BF7225 /* Client.swift in Sources */,
26BBA1971C398E3C00BF7225 /* Event.swift in Sources */,
26BBA1941C398E3C00BF7225 /* Bot.swift in Sources */,
C1A85FF91CE3BCEF00756C40 /* Client+EventDispatching.swift in Sources */,
26BBA19B1C398E3C00BF7225 /* File.swift in Sources */,
260EC2351C4DC61D0093B253 /* SlackWebAPI.swift in Sources */,
26DF40351C7A0FA300E19241 /* Attachment.swift in Sources */,
26BBA19C1C398E3C00BF7225 /* Message.swift in Sources */,
26BBA19D1C398E3C00BF7225 /* Team.swift in Sources */,
260EC2331C4DC61D0093B253 /* Extensions.swift in Sources */,
26BBA1A01C398E3C00BF7225 /* UserGroup.swift in Sources */,
2601D61B1C7646B80012BF22 /* SlackWebAPIErrorDispatcher.swift in Sources */,
C1A85FFA1CE3BCEF00756C40 /* Client+EventHandling.swift in Sources */,
260EC2341C4DC61D0093B253 /* NetworkInterface.swift in Sources */,
26BBA1981C398E3C00BF7225 /* EventDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993961CE90EE0004A6E93 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
263993971CE90EE0004A6E93 /* Client+Utilities.swift in Sources */,
263993981CE90EE0004A6E93 /* Channel.swift in Sources */,
263993991CE90EE0004A6E93 /* User.swift in Sources */,
2639939A1CE90EE0004A6E93 /* Types.swift in Sources */,
2639939B1CE90EE0004A6E93 /* Client.swift in Sources */,
2639939C1CE90EE0004A6E93 /* Event.swift in Sources */,
2639939D1CE90EE0004A6E93 /* Bot.swift in Sources */,
2639939E1CE90EE0004A6E93 /* Client+EventDispatching.swift in Sources */,
2639939F1CE90EE0004A6E93 /* File.swift in Sources */,
263993A01CE90EE0004A6E93 /* SlackWebAPI.swift in Sources */,
263993A11CE90EE0004A6E93 /* Attachment.swift in Sources */,
263993A21CE90EE0004A6E93 /* Message.swift in Sources */,
263993A31CE90EE0004A6E93 /* Team.swift in Sources */,
263993A41CE90EE0004A6E93 /* Extensions.swift in Sources */,
263993A51CE90EE0004A6E93 /* UserGroup.swift in Sources */,
263993A61CE90EE0004A6E93 /* SlackWebAPIErrorDispatcher.swift in Sources */,
263993A71CE90EE0004A6E93 /* Client+EventHandling.swift in Sources */,
263993A81CE90EE0004A6E93 /* NetworkInterface.swift in Sources */,
263993A91CE90EE0004A6E93 /* EventDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
263993B51CE90EED004A6E93 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
263993B61CE90EED004A6E93 /* Client+Utilities.swift in Sources */,
263993B71CE90EED004A6E93 /* Channel.swift in Sources */,
263993B81CE90EED004A6E93 /* User.swift in Sources */,
263993B91CE90EED004A6E93 /* Types.swift in Sources */,
263993BA1CE90EED004A6E93 /* Client.swift in Sources */,
263993BB1CE90EED004A6E93 /* Event.swift in Sources */,
263993BC1CE90EED004A6E93 /* Bot.swift in Sources */,
263993BD1CE90EED004A6E93 /* Client+EventDispatching.swift in Sources */,
263993BE1CE90EED004A6E93 /* File.swift in Sources */,
263993BF1CE90EED004A6E93 /* SlackWebAPI.swift in Sources */,
263993C01CE90EED004A6E93 /* Attachment.swift in Sources */,
263993C11CE90EED004A6E93 /* Message.swift in Sources */,
263993C21CE90EED004A6E93 /* Team.swift in Sources */,
263993C31CE90EED004A6E93 /* Extensions.swift in Sources */,
263993C41CE90EED004A6E93 /* UserGroup.swift in Sources */,
263993C51CE90EED004A6E93 /* SlackWebAPIErrorDispatcher.swift in Sources */,
263993C61CE90EED004A6E93 /* Client+EventHandling.swift in Sources */,
263993C71CE90EED004A6E93 /* NetworkInterface.swift in Sources */,
263993C81CE90EED004A6E93 /* EventDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
2601D62A1C7688610012BF22 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
2601D62B1C7688610012BF22 /* Base */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
2601D62F1C7688610012BF22 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "OSX-Sample/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "LS.OSX-Sample";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
2601D6301C7688610012BF22 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "OSX-Sample/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "LS.OSX-Sample";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
26072A3A1BB48B3B00CD650C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
26072A3B1BB48B3B00CD650C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
26072A3D1BB48B3B00CD650C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
26072A3E1BB48B3B00CD650C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = SlackKit;
SKIP_INSTALL = YES;
};
name = Release;
};
263993B01CE90EE0004A6E93 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-iOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
263993B11CE90EE0004A6E93 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-iOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
};
name = Release;
};
263993CF1CE90EED004A6E93 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/tvOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Debug;
};
263993D01CE90EED004A6E93 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/tvOS",
);
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = "$(SRCROOT)/SlackKit/Supporting Files/Info-tvOS.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = com.launchsoft.SlackKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
TVOS_DEPLOYMENT_TARGET = 9.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
2601D62E1C7688610012BF22 /* Build configuration list for PBXNativeTarget "OSX-Sample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2601D62F1C7688610012BF22 /* Debug */,
2601D6301C7688610012BF22 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
26072A2E1BB48B3A00CD650C /* Build configuration list for PBXProject "SlackKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
26072A3A1BB48B3B00CD650C /* Debug */,
26072A3B1BB48B3B00CD650C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
26072A3C1BB48B3B00CD650C /* Build configuration list for PBXNativeTarget "SlackKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
26072A3D1BB48B3B00CD650C /* Debug */,
26072A3E1BB48B3B00CD650C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
263993AF1CE90EE0004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit_iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
263993B01CE90EE0004A6E93 /* Debug */,
263993B11CE90EE0004A6E93 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
263993CE1CE90EED004A6E93 /* Build configuration list for PBXNativeTarget "SlackKit_tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
263993CF1CE90EED004A6E93 /* Debug */,
263993D01CE90EED004A6E93 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 26072A2B1BB48B3A00CD650C /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:SlackRTMKit.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "26072A331BB48B3A00CD650C"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "26072A331BB48B3A00CD650C"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "26072A331BB48B3A00CD650C"
BuildableName = "SlackKit.framework"
BlueprintName = "SlackKit"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993951CE90EE0004A6E93"
BuildableName = "SlackKit_iOS.framework"
BlueprintName = "SlackKit_iOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993951CE90EE0004A6E93"
BuildableName = "SlackKit_iOS.framework"
BlueprintName = "SlackKit_iOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993951CE90EE0004A6E93"
BuildableName = "SlackKit_iOS.framework"
BlueprintName = "SlackKit_iOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993B41CE90EED004A6E93"
BuildableName = "SlackKit_tvOS.framework"
BlueprintName = "SlackKit_tvOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993B41CE90EED004A6E93"
BuildableName = "SlackKit_tvOS.framework"
BlueprintName = "SlackKit_tvOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "263993B41CE90EED004A6E93"
BuildableName = "SlackKit_tvOS.framework"
BlueprintName = "SlackKit_tvOS"
ReferencedContainer = "container:SlackKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+30
View File
@@ -0,0 +1,30 @@
//
// SlackKit.h
//
// 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/Foundation.h>
//! Project version number for SlackKit.
FOUNDATION_EXPORT double SlackKitVersionNumber;
//! Project version string for SlackKit.
FOUNDATION_EXPORT const unsigned char SlackKitVersionString[];
+12 -10
View File
@@ -21,6 +21,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public struct Attachment {
public let fallback: String?
@@ -36,7 +38,7 @@ public struct Attachment {
public let imageURL: String?
public let thumbURL: String?
internal init?(attachment: [String: Any]?) {
internal init?(attachment: [String: AnyObject]?) {
fallback = attachment?["fallback"] as? String
color = attachment?["color"] as? String
pretext = attachment?["pretext"] as? String
@@ -48,7 +50,7 @@ public struct Attachment {
text = attachment?["text"] as? String
imageURL = attachment?["image_url"] as? String
thumbURL = attachment?["thumb_url"] as? String
fields = (attachment?["fields"] as? [Any])?.objectArrayFromDictionaryArray(intializer: {(field) -> AttachmentField? in
fields = (attachment?["fields"] as? [[String: AnyObject]])?.objectArrayFromDictionaryArray({(field) -> AttachmentField? in
return AttachmentField(field: field)
})
}
@@ -68,8 +70,8 @@ public struct Attachment {
self.thumbURL = thumbURL
}
internal func dictionary() -> [String: Any] {
var attachment = [String: Any]()
internal func dictionary() -> [String: AnyObject] {
var attachment = [String: AnyObject]()
attachment["fallback"] = fallback
attachment["color"] = color
attachment["pretext"] = pretext
@@ -79,14 +81,14 @@ public struct Attachment {
attachment["title"] = title
attachment["title_link"] = titleLink
attachment["text"] = text
attachment["fields"] = fieldJSONArray(fields: fields)
attachment["fields"] = fieldJSONArray(fields)
attachment["image_url"] = imageURL
attachment["thumb_url"] = thumbURL
return attachment
}
private func fieldJSONArray(fields: [AttachmentField]?) -> [Any] {
var returnValue = [Any]()
private func fieldJSONArray(fields: [AttachmentField]?) -> [[String: AnyObject]] {
var returnValue = [[String: AnyObject]]()
if let f = fields {
for field in f {
returnValue.append(field.dictionary())
@@ -103,7 +105,7 @@ public struct AttachmentField {
public let value: String?
public let short: Bool?
internal init?(field: [String: Any]?) {
internal init?(field: [String: AnyObject]?) {
title = field?["title"] as? String
value = field?["value"] as? String
short = field?["short"] as? Bool
@@ -115,8 +117,8 @@ public struct AttachmentField {
self.short = short
}
internal func dictionary() -> [String: Any] {
var field = [String: Any]()
internal func dictionary() -> [String: AnyObject] {
var field = [String: AnyObject]()
field["title"] = title
field["value"] = value
field["short"] = short
+3 -3
View File
@@ -25,12 +25,12 @@ public struct Bot {
public let id: String?
internal(set) public var name: String?
internal(set) public var icons: [String: Any]?
internal(set) public var icons: [String: AnyObject]?
internal init?(bot: [String: Any]?) {
internal init?(bot: [String: AnyObject]?) {
id = bot?["id"] as? String
name = bot?["name"] as? String
icons = bot?["icons"] as? [String: Any]
icons = bot?["icons"] as? [String: AnyObject]
}
}
+5 -5
View File
@@ -49,7 +49,7 @@ public struct Channel {
internal(set) public var usersTyping = [String]()
internal(set) public var messages = [String: Message]()
internal init?(channel: [String: Any]?) {
internal init?(channel: [String: AnyObject]?) {
id = channel?["id"] as? String
name = channel?["name"] as? String
created = channel?["created"] as? Int
@@ -62,8 +62,8 @@ public struct Channel {
isUserDeleted = channel?["is_user_deleted"] as? Bool
user = channel?["user"] as? String
isOpen = channel?["is_open"] as? Bool
topic = Topic(topic: channel?["topic"] as? [String: Any])
purpose = Topic(topic: channel?["purpose"] as? [String: Any])
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
unread = channel?["unread_count"] as? Int
@@ -71,10 +71,10 @@ public struct Channel {
hasPins = channel?["has_pins"] as? Bool
members = channel?["members"] as? [String]
if (Message(message: channel?["latest"] as? [String: Any])?.ts == nil) {
if (Message(message: channel?["latest"] as? [String: AnyObject])?.ts == nil) {
latest = Message(ts: channel?["latest"] as? String)
} else {
latest = Message(message: channel?["latest"] as? [String: Any])
latest = Message(message: channel?["latest"] as? [String: AnyObject])
}
}
+59 -59
View File
@@ -21,9 +21,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
internal extension SlackClient {
func dispatch(event: [String: Any]) {
internal extension Client {
func dispatch(event: [String: AnyObject]) {
let event = Event(event: event)
if let type = event.type {
switch type {
@@ -31,112 +31,112 @@ internal extension SlackClient {
connected = true
slackEventsDelegate?.clientConnected()
case .Ok:
messageSent(event: event)
messageSent(event)
case .Message:
if (event.subtype != nil) {
messageDispatcher(event: event)
messageDispatcher(event)
} else {
messageReceived(event: event)
messageReceived(event)
}
case .UserTyping:
userTyping(event: event)
userTyping(event)
case .ChannelMarked, .IMMarked, .GroupMarked:
channelMarked(event: event)
channelMarked(event)
case .ChannelCreated, .IMCreated:
channelCreated(event: event)
channelCreated(event)
case .ChannelJoined, .GroupJoined:
channelJoined(event: event)
channelJoined(event)
case .ChannelLeft, .GroupLeft:
channelLeft(event: event)
channelLeft(event)
case .ChannelDeleted:
channelDeleted(event: event)
channelDeleted(event)
case .ChannelRenamed, .GroupRename:
channelRenamed(event: event)
channelRenamed(event)
case .ChannelArchive, .GroupArchive:
channelArchived(event: event, archived: true)
channelArchived(event, archived: true)
case .ChannelUnarchive, .GroupUnarchive:
channelArchived(event: event, archived: false)
channelArchived(event, archived: false)
case .ChannelHistoryChanged, .IMHistoryChanged, .GroupHistoryChanged:
channelHistoryChanged(event: event)
channelHistoryChanged(event)
case .DNDUpdated:
doNotDisturbUpdated(event: event)
doNotDisturbUpdated(event)
case .DNDUpatedUser:
doNotDisturbUserUpdated(event: event)
doNotDisturbUserUpdated(event)
case .IMOpen, .GroupOpen:
open(event: event, open: true)
open(event, open: true)
case .IMClose, .GroupClose:
open(event: event, open: false)
open(event, open: false)
case .FileCreated:
processFile(event: event)
processFile(event)
case .FileShared:
processFile(event: event)
processFile(event)
case .FileUnshared:
processFile(event: event)
processFile(event)
case .FilePublic:
processFile(event: event)
processFile(event)
case .FilePrivate:
filePrivate(event: event)
filePrivate(event)
case .FileChanged:
processFile(event: event)
processFile(event)
case .FileDeleted:
deleteFile(event: event)
deleteFile(event)
case .FileCommentAdded:
fileCommentAdded(event: event)
fileCommentAdded(event)
case .FileCommentEdited:
fileCommentEdited(event: event)
fileCommentEdited(event)
case .FileCommentDeleted:
fileCommentDeleted(event: event)
fileCommentDeleted(event)
case .PinAdded:
pinAdded(event: event)
pinAdded(event)
case .PinRemoved:
pinRemoved(event: event)
pinRemoved(event)
case .Pong:
pong(event: event)
pong(event)
case .PresenceChange:
presenceChange(event: event)
presenceChange(event)
case .ManualPresenceChange:
manualPresenceChange(event: event)
manualPresenceChange(event)
case .PrefChange:
changePreference(event: event)
changePreference(event)
case .UserChange:
userChange(event: event)
userChange(event)
case .TeamJoin:
teamJoin(event: event)
teamJoin(event)
case .StarAdded:
itemStarred(event: event, star: true)
itemStarred(event, star: true)
case .StarRemoved:
itemStarred(event: event, star: false)
itemStarred(event, star: false)
case .ReactionAdded:
addedReaction(event: event)
addedReaction(event)
case .ReactionRemoved:
removedReaction(event: event)
removedReaction(event)
case .EmojiChanged:
emojiChanged(event: event)
emojiChanged(event)
case .CommandsChanged:
// This functionality is only used by our web client.
// The other APIs required to support slash command metadata are currently unstable.
// Until they are released other clients should ignore this event.
break
case .TeamPlanChange:
teamPlanChange(event: event)
teamPlanChange(event)
case .TeamPrefChange:
teamPreferenceChange(event: event)
teamPreferenceChange(event)
case .TeamRename:
teamNameChange(event: event)
teamNameChange(event)
case .TeamDomainChange:
teamDomainChange(event: event)
teamDomainChange(event)
case .EmailDomainChange:
emailDomainChange(event: event)
emailDomainChange(event)
case .TeamProfileChange:
teamProfileChange(event: event)
teamProfileChange(event)
case .TeamProfileDelete:
teamProfileDeleted(event: event)
teamProfileDeleted(event)
case .TeamProfileReorder:
teamProfileReordered(event: event)
teamProfileReordered(event)
case .BotAdded:
bot(event: event)
bot(event)
case .BotChanged:
bot(event: event)
bot(event)
case .AccountsChanged:
// The accounts_changed event is used by our web client to maintain a list of logged-in accounts.
// Other clients should ignore this event.
@@ -147,11 +147,11 @@ internal extension SlackClient {
// The reconnect_url event is currently unsupported and experimental.
break
case .SubteamCreated, .SubteamUpdated:
subteam(event: event)
subteam(event)
case .SubteamSelfAdded:
subteamAddedSelf(event: event)
subteamAddedSelf(event)
case.SubteamSelfRemoved:
subteamRemovedSelf(event: event)
subteamRemovedSelf(event)
case .Error:
print("Error: \(event)")
break
@@ -163,11 +163,11 @@ internal extension SlackClient {
let subtype = MessageSubtype(rawValue: event.subtype!)!
switch subtype {
case .MessageChanged:
messageChanged(event: event)
messageChanged(event)
case .MessageDeleted:
messageDeleted(event: event)
messageDeleted(event)
default:
messageReceived(event: event)
messageReceived(event)
}
}
+73 -70
View File
@@ -21,10 +21,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Venice
import Foundation
internal extension Client {
internal extension SlackClient {
//MARK: - Pong
func pong(event: Event) {
pong = event.replyTo
@@ -32,12 +32,12 @@ internal extension SlackClient {
//MARK: - Messages
func messageSent(event: Event) {
if let reply = event.replyTo, message = sentMessages["\(reply)"], channel = message.channel, ts = message.ts {
if let reply = event.replyTo, message = sentMessages[NSNumber(double: reply).stringValue], channel = message.channel, ts = message.ts {
message.ts = event.ts
message.text = event.text
channels[channel]?.messages[ts] = message
messageEventsDelegate?.messageSent(message: message)
messageEventsDelegate?.messageSent(message)
}
}
@@ -45,7 +45,7 @@ internal extension SlackClient {
if let channel = event.channel, message = event.message, id = channel.id, ts = message.ts {
channels[id]?.messages[ts] = message
messageEventsDelegate?.messageReceived(message: message)
messageEventsDelegate?.messageReceived(message)
}
}
@@ -53,16 +53,16 @@ internal extension SlackClient {
if let id = event.channel?.id, nested = event.nestedMessage, ts = nested.ts {
channels[id]?.messages[ts] = nested
messageEventsDelegate?.messageChanged(message: nested)
messageEventsDelegate?.messageChanged(nested)
}
}
func messageDeleted(event: Event) {
if let id = event.channel?.id, key = event.message?.deletedTs {
let message = channels[id]?.messages[key]
channels[id]?.messages.removeValue(forKey:key)
channels[id]?.messages.removeValueForKey(key)
messageEventsDelegate?.messageDeleted(message: message)
messageEventsDelegate?.messageDeleted(message)
}
}
@@ -73,15 +73,14 @@ internal extension SlackClient {
if (!channels[channelID]!.usersTyping.contains(userID)) {
channels[channelID]?.usersTyping.append(userID)
channelEventsDelegate?.userTyping(channel: event.channel, user: event.user)
channelEventsDelegate?.userTyping(event.channel, user: event.user)
}
}
co { [weak self] in
let weakSelf = self
nap(for: 5.0.seconds)
if let index = weakSelf?.channels[channelID]?.usersTyping.index(of:userID) {
weakSelf?.channels[channelID]?.usersTyping.remove(at: index)
let timeout = dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC)))
dispatch_after(timeout, dispatch_get_main_queue()) {
if let index = self.channels[channelID]?.usersTyping.indexOf(userID) {
self.channels[channelID]?.usersTyping.removeAtIndex(index)
}
}
}
@@ -91,7 +90,7 @@ internal extension SlackClient {
if let channel = event.channel, id = channel.id {
channels[id]?.lastRead = event.ts
channelEventsDelegate?.channelMarked(channel: channel, timestamp: event.ts)
channelEventsDelegate?.channelMarked(channel, timestamp: event.ts)
}
//TODO: Recalculate unreads
}
@@ -100,15 +99,15 @@ internal extension SlackClient {
if let channel = event.channel, id = channel.id {
channels[id] = channel
channelEventsDelegate?.channelCreated(channel: channel)
channelEventsDelegate?.channelCreated(channel)
}
}
func channelDeleted(event: Event) {
if let channel = event.channel, id = channel.id {
channels.removeValue(forKey:id)
channels.removeValueForKey(id)
channelEventsDelegate?.channelDeleted(channel: channel)
channelEventsDelegate?.channelDeleted(channel)
}
}
@@ -116,16 +115,16 @@ internal extension SlackClient {
if let channel = event.channel, id = channel.id {
channels[id] = event.channel
channelEventsDelegate?.channelJoined(channel: channel)
channelEventsDelegate?.channelJoined(channel)
}
}
func channelLeft(event: Event) {
if let channel = event.channel, id = channel.id, userID = authenticatedUser?.id {
if let index = channels[id]?.members?.index(of:userID) {
channels[id]?.members?.remove(at: index)
if let index = channels[id]?.members?.indexOf(userID) {
channels[id]?.members?.removeAtIndex(index)
channelEventsDelegate?.channelLeft(channel: channel)
channelEventsDelegate?.channelLeft(channel)
}
}
}
@@ -134,7 +133,7 @@ internal extension SlackClient {
if let channel = event.channel, id = channel.id {
channels[id]?.name = channel.name
channelEventsDelegate?.channelRenamed(channel: channel)
channelEventsDelegate?.channelRenamed(channel)
}
}
@@ -142,7 +141,7 @@ internal extension SlackClient {
if let channel = event.channel, id = channel.id {
channels[id]?.isArchived = archived
channelEventsDelegate?.channelArchived(channel: channel)
channelEventsDelegate?.channelArchived(channel)
}
}
@@ -150,7 +149,7 @@ internal extension SlackClient {
if let channel = event.channel {
//TODO: Reload chat history if there are any cached messages before latest
channelEventsDelegate?.channelHistoryChanged(channel: channel)
channelEventsDelegate?.channelHistoryChanged(channel)
}
}
@@ -159,7 +158,7 @@ internal extension SlackClient {
if let dndStatus = event.dndStatus {
authenticatedUser?.doNotDisturbStatus = dndStatus
doNotDisturbEventsDelegate?.doNotDisturbUpdated(dndStatus: dndStatus)
doNotDisturbEventsDelegate?.doNotDisturbUpdated(dndStatus)
}
}
@@ -167,7 +166,7 @@ internal extension SlackClient {
if let dndStatus = event.dndStatus, user = event.user, id = user.id {
users[id]?.doNotDisturbStatus = dndStatus
doNotDisturbEventsDelegate?.doNotDisturbUserUpdated(dndStatus: dndStatus, user: user)
doNotDisturbEventsDelegate?.doNotDisturbUserUpdated(dndStatus, user: user)
}
}
@@ -176,7 +175,7 @@ internal extension SlackClient {
if let channel = event.channel, id = channel.id {
channels[id]?.isOpen = open
groupEventsDelegate?.groupOpened(group: channel)
groupEventsDelegate?.groupOpened(channel)
}
}
@@ -191,7 +190,7 @@ internal extension SlackClient {
files[id] = file
fileEventsDelegate?.fileProcessed(file: file)
fileEventsDelegate?.fileProcessed(file)
}
}
@@ -199,17 +198,17 @@ internal extension SlackClient {
if let file = event.file, id = file.id {
files[id]?.isPublic = false
fileEventsDelegate?.fileMadePrivate(file: file)
fileEventsDelegate?.fileMadePrivate(file)
}
}
func deleteFile(event: Event) {
if let file = event.file, id = file.id {
if files[id] != nil {
files.removeValue(forKey:id)
files.removeValueForKey(id)
}
fileEventsDelegate?.fileDeleted(file: file)
fileEventsDelegate?.fileDeleted(file)
}
}
@@ -217,7 +216,7 @@ internal extension SlackClient {
if let file = event.file, id = file.id, comment = event.comment, commentID = comment.id {
files[id]?.comments[commentID] = comment
fileEventsDelegate?.fileCommentAdded(file: file, comment: comment)
fileEventsDelegate?.fileCommentAdded(file, comment: comment)
}
}
@@ -225,15 +224,15 @@ internal extension SlackClient {
if let file = event.file, id = file.id, comment = event.comment, commentID = comment.id {
files[id]?.comments[commentID]?.comment = comment.comment
fileEventsDelegate?.fileCommentEdited(file: file, comment: comment)
fileEventsDelegate?.fileCommentEdited(file, comment: comment)
}
}
func fileCommentDeleted(event: Event) {
if let file = event.file, id = file.id, comment = event.comment, commentID = comment.id {
files[id]?.comments.removeValue(forKey:commentID)
files[id]?.comments.removeValueForKey(commentID)
fileEventsDelegate?.fileCommentDeleted(file: file, comment: comment)
fileEventsDelegate?.fileCommentDeleted(file, comment: comment)
}
}
@@ -242,7 +241,7 @@ internal extension SlackClient {
if let id = event.channelID, item = event.item {
channels[id]?.pinnedItems.append(item)
pinEventsDelegate?.itemPinned(item: item, channel: channels[id])
pinEventsDelegate?.itemPinned(item, channel: channels[id])
}
}
@@ -252,7 +251,7 @@ internal extension SlackClient {
channels[id]?.pinnedItems = pins
}
pinEventsDelegate?.itemUnpinned(item: event.item, channel: channels[id])
pinEventsDelegate?.itemUnpinned(event.item, channel: channels[id])
}
}
@@ -261,16 +260,16 @@ internal extension SlackClient {
if let item = event.item, type = item.type {
switch type {
case "message":
starMessage(item: item, star: star)
starMessage(item, star: star)
case "file":
starFile(item: item, star: star)
starFile(item, star: star)
case "file_comment":
starComment(item: item)
starComment(item)
default:
break
}
starEventsDelegate?.itemStarred(item: item, star: star)
starEventsDelegate?.itemStarred(item, star: star)
}
}
@@ -338,7 +337,7 @@ internal extension SlackClient {
break
}
reactionEventsDelegate?.reactionAdded(reaction: event.reaction, item: event.item, itemUser: event.itemUser)
reactionEventsDelegate?.reactionAdded(event.reaction, item: event.item, itemUser: event.itemUser)
}
}
@@ -349,29 +348,29 @@ internal extension SlackClient {
if let channel = item.channel, ts = item.ts {
if let message = channels[channel]?.messages[ts] {
if (message.reactions[key]) != nil {
message.reactions[key]?.users.removeValue(forKey:userID)
message.reactions[key]?.users.removeValueForKey(userID)
}
if (message.reactions[key]?.users.count == 0) {
message.reactions.removeValue(forKey:key)
message.reactions.removeValueForKey(key)
}
}
}
case "file":
if let itemFile = item.file, id = itemFile.id, file = files[id] {
if file.reactions[key] != nil {
files[id]?.reactions[key]?.users.removeValue(forKey:userID)
files[id]?.reactions[key]?.users.removeValueForKey(userID)
}
if files[id]?.reactions[key]?.users.count == 0 {
files[id]?.reactions.removeValue(forKey:key)
files[id]?.reactions.removeValueForKey(key)
}
}
case "file_comment":
if let id = item.file?.id, file = files[id], commentID = item.fileCommentID {
if file.comments[commentID]?.reactions[key] != nil {
files[id]?.comments[commentID]?.reactions[key]?.users.removeValue(forKey:userID)
files[id]?.comments[commentID]?.reactions[key]?.users.removeValueForKey(userID)
}
if files[id]?.comments[commentID]?.reactions[key]?.users.count == 0 {
files[id]?.comments[commentID]?.reactions.removeValue(forKey:key)
files[id]?.comments[commentID]?.reactions.removeValueForKey(key)
}
}
break
@@ -379,7 +378,7 @@ internal extension SlackClient {
break
}
reactionEventsDelegate?.reactionRemoved(reaction: event.reaction, item: event.item, itemUser: event.itemUser)
reactionEventsDelegate?.reactionAdded(event.reaction, item: event.item, itemUser: event.itemUser)
}
}
@@ -388,7 +387,9 @@ internal extension SlackClient {
if let name = event.name {
authenticatedUser?.preferences?[name] = event.value
slackEventsDelegate?.preferenceChanged(preference: name, value: event.value)
if let value = event.value {
slackEventsDelegate?.preferenceChanged(name, value: value)
}
}
}
@@ -399,7 +400,7 @@ internal extension SlackClient {
users[id] = user
users[id]?.preferences = preferences
slackEventsDelegate?.userChanged(user: user)
slackEventsDelegate?.userChanged(user)
}
}
@@ -408,7 +409,7 @@ internal extension SlackClient {
if let user = event.user, id = user.id {
users[id]?.presence = event.presence
slackEventsDelegate?.presenceChanged(user: user, presence: event.presence)
slackEventsDelegate?.presenceChanged(user, presence: event.presence)
}
}
@@ -417,7 +418,7 @@ internal extension SlackClient {
if let user = event.user, id = user.id {
users[id] = user
teamEventsDelegate?.teamJoined(user: user)
teamEventsDelegate?.teamJoined(user)
}
}
@@ -425,7 +426,7 @@ internal extension SlackClient {
if let plan = event.plan {
team?.plan = plan
teamEventsDelegate?.teamPlanChanged(plan: plan)
teamEventsDelegate?.teamPlanChanged(plan)
}
}
@@ -433,7 +434,9 @@ internal extension SlackClient {
if let name = event.name {
team?.prefs?[name] = event.value
teamEventsDelegate?.teamPreferencesChanged(preference: name, value: event.value)
if let value = event.value {
teamEventsDelegate?.teamPreferencesChanged(name, value: value)
}
}
}
@@ -441,7 +444,7 @@ internal extension SlackClient {
if let name = event.name {
team?.name = name
teamEventsDelegate?.teamNameChanged(name: name)
teamEventsDelegate?.teamNameChanged(name)
}
}
@@ -449,7 +452,7 @@ internal extension SlackClient {
if let domain = event.domain {
team?.domain = domain
teamEventsDelegate?.teamDomainChanged(domain: domain)
teamEventsDelegate?.teamDomainChanged(domain)
}
}
@@ -457,7 +460,7 @@ internal extension SlackClient {
if let domain = event.emailDomain {
team?.emailDomain = domain
teamEventsDelegate?.teamEmailDomainChanged(domain: domain)
teamEventsDelegate?.teamEmailDomainChanged(domain)
}
}
@@ -472,7 +475,7 @@ internal extension SlackClient {
if let bot = event.bot, id = bot.id {
bots[id] = bot
slackEventsDelegate?.botEvent(bot: bot)
slackEventsDelegate?.botEvent(bot)
}
}
@@ -481,7 +484,7 @@ internal extension SlackClient {
if let subteam = event.subteam, id = subteam.id {
userGroups[id] = subteam
subteamEventsDelegate?.subteamEvent(userGroup: subteam)
subteamEventsDelegate?.subteamEvent(subteam)
}
}
@@ -490,15 +493,15 @@ internal extension SlackClient {
if let subteamID = event.subteamID, _ = authenticatedUser?.userGroups {
authenticatedUser?.userGroups![subteamID] = subteamID
subteamEventsDelegate?.subteamSelfAdded(subteamID: subteamID)
subteamEventsDelegate?.subteamSelfAdded(subteamID)
}
}
func subteamRemovedSelf(event: Event) {
if let subteamID = event.subteamID {
authenticatedUser?.userGroups?.removeValue(forKey:subteamID)
authenticatedUser?.userGroups?.removeValueForKey(subteamID)
subteamEventsDelegate?.subteamSelfRemoved(subteamID: subteamID)
subteamEventsDelegate?.subteamSelfRemoved(subteamID)
}
}
@@ -507,12 +510,12 @@ internal extension SlackClient {
for user in users {
if let fields = event.profile?.fields {
for key in fields.keys {
users[user.0]?.profile?.customProfile?.fields[key]?.updateProfileField(profile: fields[key])
users[user.0]?.profile?.customProfile?.fields[key]?.updateProfileField(fields[key])
}
}
}
teamProfileEventsDelegate?.teamProfileChanged(profile: event.profile)
teamProfileEventsDelegate?.teamProfileChanged(event.profile)
}
func teamProfileDeleted(event: Event) {
@@ -522,7 +525,7 @@ internal extension SlackClient {
}
}
teamProfileEventsDelegate?.teamProfileDeleted(profile: event.profile)
teamProfileEventsDelegate?.teamProfileDeleted(event.profile)
}
func teamProfileReordered(event: Event) {
@@ -534,14 +537,14 @@ internal extension SlackClient {
}
}
teamProfileEventsDelegate?.teamProfileReordered(profile: event.profile)
teamProfileEventsDelegate?.teamProfileReordered(event.profile)
}
//MARK: - Authenticated User
func manualPresenceChange(event: Event) {
authenticatedUser?.presence = event.presence
slackEventsDelegate?.manualPresenceChanged(user: authenticatedUser, presence: event.presence)
slackEventsDelegate?.manualPresenceChanged(authenticatedUser, presence: event.presence)
}
}
+11 -9
View File
@@ -21,32 +21,34 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
extension SlackClient {
import Foundation
public extension Client {
//MARK: - User & Channel
public func getChannelIDByName(name: String) -> String? {
return channels.filter{$0.1.name == stripString(string: name)}.first?.0
return channels.filter{$0.1.name == stripString(name)}.first?.0
}
public func getUserIDByName(name: String) -> String? {
return users.filter{$0.1.name == stripString(string: name)}.first?.0
return users.filter{$0.1.name == stripString(name)}.first?.0
}
public func getImIDForUserWithID(id: String, success: (imID: String?)->Void, failure: (error: SlackError)->Void) {
let ims = channels.filter{$0.1.isIM == true}
let channel = ims.filter{$0.1.user == id}.first
if let channel = channel {
success(imID: channel.0)
} else {
webAPI.openIM(userID: id, success: success, failure: failure)
webAPI.openIM(id, success: success, failure: failure)
}
}
//MARK: - Utilities
internal func stripString(string: String) -> String? {
var strippedString = string
if string[string.startIndex] == "@" || string[string.startIndex] == "#" {
strippedString.characters.remove(at: string.startIndex)
strippedString = string.substringFromIndex(string.startIndex.advancedBy(1))
}
return strippedString
}
+98 -108
View File
@@ -21,12 +21,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import C7
import Jay
import Venice
import WebSocketClient
import Foundation
import Starscream
public class SlackClient {
public class Client: WebSocketDelegate {
internal(set) public var connected = false
internal(set) public var authenticated = false
@@ -54,119 +52,116 @@ public class SlackClient {
public weak var subteamEventsDelegate: SubteamEventsDelegate?
public weak var teamProfileEventsDelegate: TeamProfileEventsDelegate?
internal var token = "SLACK_AUTH_TOKEN"
public var token = "SLACK_AUTH_TOKEN"
public func setAuthToken(token: String) {
self.token = token
}
public var webAPI: SlackWebAPI {
return SlackWebAPI(slackClient: self)
return SlackWebAPI(client: self)
}
internal var webSocket: Client?
internal var socket: WebSocket?
internal var webSocket: WebSocket?
internal let api = NetworkInterface()
private let pingPongQueue = dispatch_queue_create("com.launchsoft.SlackKit", DISPATCH_QUEUE_SERIAL)
internal var ping: Double?
internal var pong: Double?
internal var pingInterval: Double?
internal var timeout: Double?
internal var pingInterval: NSTimeInterval?
internal var timeout: NSTimeInterval?
internal var reconnect: Bool?
required public init(apiToken: String) {
self.token = apiToken
}
public func connect(simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, pingInterval: Double? = nil, timeout: Double? = nil, reconnect: Bool? = nil) {
public func connect(simpleLatest simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, pingInterval: NSTimeInterval? = nil, timeout: NSTimeInterval? = nil, reconnect: Bool? = nil) {
self.pingInterval = pingInterval
self.timeout = timeout
self.reconnect = reconnect
webAPI.rtmStart(simpleLatest: simpleLatest, noUnreads: noUnreads, mpimAware: mpimAware, success: {
webAPI.rtmStart(simpleLatest, noUnreads: noUnreads, mpimAware: mpimAware, success: {
(response) -> Void in
self.initialSetup(json: response)
self.initialSetup(response)
if let socketURL = response["url"] as? String {
do {
let uri = try URI(socketURL)
self.webSocket = try Client(uri: uri, didConnect: {(socket) in
self.setupSocket(socket: socket)
if let pingInterval = self.pingInterval {
self.pingRTMServerAtInterval(interval: pingInterval)
}
})
try self.webSocket?.connect(uri.description)
} catch _ {
}
let url = NSURL(string: socketURL)
self.webSocket = WebSocket(url: url!)
self.webSocket?.delegate = self
self.webSocket?.connect()
}
}, failure:nil)
}, failure: {(error) -> Void in
self.slackEventsDelegate?.clientConnectionFailed(error)
})
}
/*TO-DO: Bug in Zewo/WebSocket
public func disconnect() {
_ = try? socket?.close()
}*/
webSocket?.disconnect()
}
//MARK: - RTM Message send
public func sendMessage(message: String, channelID: String) {
if (connected) {
if let data = formatMessageToSlackJsonString(message: message, channel: channelID) {
if let string = try? data.string() {
_ = try? socket?.send(string)
if let data = formatMessageToSlackJsonString(msg: message, channel: channelID) {
if let string = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
webSocket?.writeString(string)
}
}
}
}
private func formatMessageToSlackJsonString(message: String, channel: String) -> Data? {
let json: [String: Any] = [
"id": Time.slackTimestamp(),
private func formatMessageToSlackJsonString(message: (msg: String, channel: String)) -> NSData? {
let json: [String: AnyObject] = [
"id": NSDate().slackTimestamp(),
"type": "message",
"channel": channel,
"text": message.slackFormatEscaping()
"channel": message.channel,
"text": message.msg.slackFormatEscaping()
]
addSentMessage(json)
do {
let bytes = try Jay().dataFromJson(json)
return Data(bytes)
} catch {
let data = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted)
return data
}
catch _ {
return nil
}
}
private func addSentMessage(dictionary: [String: Any]) {
private func addSentMessage(dictionary: [String: AnyObject]) {
var message = dictionary
let ts = message["id"] as? Int
message.removeValue(forKey:"id")
message["ts"] = "\(ts)"
let ts = message["id"] as? NSNumber
message.removeValueForKey("id")
message["ts"] = ts?.stringValue
message["user"] = self.authenticatedUser?.id
sentMessages["\(ts)"] = Message(message: message)
sentMessages[ts!.stringValue] = Message(message: message)
}
//MARK: - RTM Ping
private func pingRTMServerAtInterval(interval: Double) {
co { [weak self] in
let weakSelf = self
repeat {
nap(for: interval)
weakSelf?.sendRTMPing()
} while weakSelf?.connected == true && weakSelf?.timeoutCheck() == true
//weakSelf?.disconnect()
}
private func pingRTMServerAtInterval(interval: NSTimeInterval) {
let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC)))
dispatch_after(delay, pingPongQueue, {
if self.connected && self.timeoutCheck() {
self.sendRTMPing()
self.pingRTMServerAtInterval(interval)
} else {
self.disconnect()
}
})
}
private func sendRTMPing() {
if connected {
let json: [String: Any] = [
"id": Double.slackTimestamp(),
let json: [String: AnyObject] = [
"id": NSDate().slackTimestamp(),
"type": "ping",
]
do {
let data = try Jay().dataFromJson(json)
let string = try data.string()
ping = json["id"] as? Double
try socket?.send(string)
let data = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted)
let string = NSString(data: data, encoding: NSUTF8StringEncoding)
if let writePing = string as? String {
ping = json["id"] as? Double
webSocket?.writeString(writePing)
}
}
catch _ {
@@ -188,42 +183,42 @@ public class SlackClient {
}
//MARK: - Client setup
private func initialSetup(json: [String: Any]) {
team = Team(team: json["team"] as? [String: Any])
authenticatedUser = User(user: json["self"] as? [String: Any])
authenticatedUser?.doNotDisturbStatus = DoNotDisturbStatus(status: json["dnd"] as? [String: Any])
enumerateObjects(array: json["users"] as? Array) { (user) in self.addUser(aUser: user) }
enumerateObjects(array: json["channels"] as? Array) { (channel) in self.addChannel(aChannel: channel) }
enumerateObjects(array: json["groups"] as? Array) { (group) in self.addChannel(aChannel: group) }
enumerateObjects(array: json["mpims"] as? Array) { (mpim) in self.addChannel(aChannel: mpim) }
enumerateObjects(array: json["ims"] as? Array) { (ims) in self.addChannel(aChannel: ims) }
enumerateObjects(array: json["bots"] as? Array) { (bots) in self.addBot(aBot: bots) }
enumerateSubteams(subteams: json["subteams"] as? [String: Any])
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])
enumerateObjects(json["users"] as? Array) { (user) in self.addUser(user) }
enumerateObjects(json["channels"] as? Array) { (channel) in self.addChannel(channel) }
enumerateObjects(json["groups"] as? Array) { (group) in self.addChannel(group) }
enumerateObjects(json["mpims"] as? Array) { (mpim) in self.addChannel(mpim) }
enumerateObjects(json["ims"] as? Array) { (ims) in self.addChannel(ims) }
enumerateObjects(json["bots"] as? Array) { (bots) in self.addBot(bots) }
enumerateSubteams(json["subteams"] as? [String: AnyObject])
}
private func addUser(aUser: [String: Any]) {
private func addUser(aUser: [String: AnyObject]) {
if let user = User(user: aUser), id = user.id {
users[id] = user
}
}
private func addChannel(aChannel: [String: Any]) {
private func addChannel(aChannel: [String: AnyObject]) {
if let channel = Channel(channel: aChannel), id = channel.id {
channels[id] = channel
}
}
private func addBot(aBot: [String: Any]) {
private func addBot(aBot: [String: AnyObject]) {
if let bot = Bot(bot: aBot), id = bot.id {
bots[id] = bot
}
}
private func enumerateSubteams(subteams: [String: Any]?) {
private func enumerateSubteams(subteams: [String: AnyObject]?) {
if let subteams = subteams {
if let all = subteams["all"] as? [Any] {
if let all = subteams["all"] as? [[String: AnyObject]] {
for item in all {
let u = UserGroup(userGroup: item as? [String: Any])
let u = UserGroup(userGroup: item)
self.userGroups[u!.id!] = u
}
}
@@ -237,48 +232,27 @@ public class SlackClient {
}
// MARK: - Utilities
private func enumerateObjects(array: [Any]?, initalizer: ([String: Any])-> Void) {
private func enumerateObjects(array: [AnyObject]?, initalizer: ([String: AnyObject])-> Void) {
if let array = array {
for object in array {
if let dictionary = object as? [String: Any] {
if let dictionary = object as? [String: AnyObject] {
initalizer(dictionary)
}
}
}
}
// MARK: - WebSocket
private func setupSocket(socket: WebSocket) {
socket.onText {(message) in
self.websocketDidReceive(message: message)
// MARK: - WebSocketDelegate
public func websocketDidConnect(socket: WebSocket) {
if let pingInterval = pingInterval {
pingRTMServerAtInterval(pingInterval)
}
socket.onPing { (data) in try socket.pong() }
socket.onPong { (data) in try socket.ping() }
socket.onClose{ (code: CloseCode?, reason: String?) in
self.websocketDidDisconnect(closeCode: code, error: reason)
}
self.socket = socket
}
private func websocketDidReceive(message: String) {
do {
let json = try Jay().jsonFromData(message.data.bytes)
if let event = json as? [String: Any] {
dispatch(event:event)
}
}
catch _ {
}
}
private func websocketDidDisconnect(closeCode: CloseCode?, error: String?) {
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
connected = false
authenticated = false
webSocket = nil
socket = nil
authenticatedUser = nil
slackEventsDelegate?.clientDisconnected()
if reconnect == true {
@@ -286,4 +260,20 @@ public class SlackClient {
}
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
guard let data = text.dataUsingEncoding(NSUTF8StringEncoding) else {
return
}
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as? [String: AnyObject] {
dispatch(json)
}
}
catch _ {
}
}
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {}
}
+20 -18
View File
@@ -1,5 +1,5 @@
//
// Message.swift
// Event.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
@@ -137,13 +137,14 @@ internal struct Event {
let fileID: String?
let presence: String?
let name: String?
let value: Any?
let value: AnyObject?
let plan: String?
let url: String?
let domain: String?
let emailDomain: String?
let reaction: String?
let replyTo: Double?
let reactions: [[String: AnyObject]]?
let edited: Edited?
let bot: Bot?
let channel: Channel?
@@ -159,7 +160,7 @@ internal struct Event {
let subteamID: String?
var profile: CustomProfile?
init(event:[String: Any]) {
init(event:[String: AnyObject]) {
if let eventType = event["type"] as? String {
type = EventType(rawValue:eventType)
} else {
@@ -185,40 +186,41 @@ internal struct Event {
emailDomain = event["email_domain"] as? String
reaction = event["reaction"] as? String
replyTo = event["reply_to"] as? Double
bot = Bot(bot: event["bot"] as? [String: Any])
edited = Edited(edited:event["edited"] as? [String: Any])
dndStatus = DoNotDisturbStatus(status: event["dnd_status"] as? [String: Any])
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])
itemUser = event["item_user"] as? String
item = Item(item: event["item"] as? [String: Any])
subteam = UserGroup(userGroup: event["subteam"] as? [String: Any])
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? [String: Any])
profile = CustomProfile(profile: event["profile"] as? [String: Any])
nestedMessage = Message(message: event["message"] as? [String: AnyObject])
profile = CustomProfile(profile: event["profile"] as? [String: AnyObject])
// Comment, Channel, User, and File can come across as Strings or Dictionaries
if (Comment(comment: event["comment"] as? [String: Any])?.id == 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? [String: Any])
comment = Comment(comment: event["comment"] as? [String: AnyObject])
}
if (User(user: event["user"] as? [String: Any])?.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? [String: Any])
user = User(user: event["user"] as? [String: AnyObject])
}
if (File(file: event["file"] as? [String: Any])?.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? [String: Any])
file = File(file: event["file"] as? [String: AnyObject])
}
if (Channel(channel: event["channel"] as? [String: Any])?.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? [String: Any])
channel = Channel(channel: event["channel"] as? [String: AnyObject])
}
}
+5 -2
View File
@@ -21,10 +21,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public protocol SlackEventsDelegate: class {
func clientConnectionFailed(error: SlackError)
func clientConnected()
func clientDisconnected()
func preferenceChanged(preference: String, value: Any)
func preferenceChanged(preference: String, value: AnyObject)
func userChanged(user: User)
func presenceChanged(user: User?, presence: String?)
func manualPresenceChanged(user: User?, presence: String?)
@@ -85,7 +88,7 @@ public protocol ReactionEventsDelegate: class {
public protocol TeamEventsDelegate: class {
func teamJoined(user: User)
func teamPlanChanged(plan: String)
func teamPreferencesChanged(preference: String, value: Any)
func teamPreferencesChanged(preference: String, value: AnyObject)
func teamNameChanged(name: String)
func teamDomainChanged(domain: String)
func teamEmailDomainChanged(domain: String)
+9 -49
View File
@@ -21,30 +21,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import C7
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif
import Foundation
public typealias Time=Double
public extension NSDate {
public extension Double {
static func slackTimestamp() -> Double {
#if os(Linux)
return Double(time(nil))
#else
var clock: clock_serv_t = clock_serv_t()
var timeSpecBuffer: mach_timespec_t = mach_timespec_t(tv_sec: 0, tv_nsec: 0)
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock)
clock_get_time(clock, &timeSpecBuffer)
mach_port_deallocate(mach_task_self_, clock)
return Double(timeSpecBuffer.tv_sec) + Double(timeSpecBuffer.tv_nsec) * 0.000000001
#endif
func slackTimestamp() -> Double {
return NSNumber(double: timeIntervalSince1970).doubleValue
}
}
@@ -52,42 +34,20 @@ public extension Double {
internal extension String {
func slackFormatEscaping() -> String {
var escapedString = self
escapedString.replace(string: "&", with: "&amp;")
escapedString.replace(string: "<", with: "&lt;")
escapedString.replace(string: ">", with: "&gt;")
var escapedString = stringByReplacingOccurrencesOfString("&", withString: "&amp;")
escapedString = stringByReplacingOccurrencesOfString("<", withString: "&lt;")
escapedString = stringByReplacingOccurrencesOfString(">", withString: "&gt;")
return escapedString
}
}
public extension String {
func contains(query: String, caseSensitive: Bool = false) -> Bool {
if query.isEmpty { return true }
let (s, q) = caseSensitive ? (self, query) : (self.lowercased(), query.lowercased())
var chars = s.characters; let qchars = q.characters
while !chars.isEmpty {
if chars.starts(with: qchars) { return true }
chars.removeFirst()
}
return false
}
func prefixedBy(query: String, caseSensitive: Bool = false) -> Bool {
let (s, q) = caseSensitive ? (self, query) : (self.lowercased(), query.lowercased())
return s.characters.starts(with: q.characters)
}
}
internal extension Array {
func objectArrayFromDictionaryArray<T>(intializer:([String: Any])->T?) -> [T] {
func objectArrayFromDictionaryArray<T>(intializer:([String: AnyObject])->T?) -> [T] {
var returnValue = [T]()
for object in self {
if let dictionary = object as? [String: Any] {
if let dictionary = object as? [String: AnyObject] {
if let value = intializer(dictionary) {
returnValue.append(value)
}
+52 -4
View File
@@ -44,6 +44,22 @@ public struct File {
public let thumb360gif: String?
public let thumb360w: String?
public let thumb360h: String?
public let thumb480: String?
public let thumb480gif: String?
public let thumb480w: String?
public let thumb480h: String?
public let thumb720: String?
public let thumb720gif: String?
public let thumb720w: String?
public let thumb720h: String?
public let thumb960: String?
public let thumb960gif: String?
public let thumb960w: String?
public let thumb960h: String?
public let thumb1024: String?
public let thumb1024gif: String?
public let thumb1024w: String?
public let thumb1024h: String?
public let permalink: String?
public let editLink: String?
public let preview: String?
@@ -62,7 +78,7 @@ public struct File {
internal(set) public var comments = [String: Comment]()
internal(set) public var reactions = [String: Reaction]()
public init?(file:[String: Any]?) {
public init?(file:[String: AnyObject]?) {
id = file?["id"] as? String
created = file?["created"] as? Int
name = file?["name"] as? String
@@ -84,6 +100,22 @@ public struct File {
thumb360gif = file?["thumb_360_gif"] as? String
thumb360w = file?["thumb_360_w"] as? String
thumb360h = file?["thumb_360_h"] as? String
thumb480 = file?["thumb_480"] as? String
thumb480gif = file?["thumb_480_gif"] as? String
thumb480w = file?["thumb_480_w"] as? String
thumb480h = file?["thumb_480_h"] as? String
thumb720 = file?["thumb_720"] as? String
thumb720gif = file?["thumb_720_gif"] as? String
thumb720w = file?["thumb_720_w"] as? String
thumb720h = file?["thumb_720_h"] as? String
thumb960 = file?["thumb_960"] as? String
thumb960gif = file?["thumb_960_gif"] as? String
thumb960w = file?["thumb_960_w"] as? String
thumb960h = file?["thumb_960_h"] as? String
thumb1024 = file?["thumb_1024"] as? String
thumb1024gif = file?["thumb_1024_gif"] as? String
thumb1024w = file?["thumb_1024_w"] as? String
thumb1024h = file?["thumb_1024_h"] as? String
permalink = file?["permalink"] as? String
editLink = file?["edit_link"] as? String
preview = file?["preview"] as? String
@@ -95,12 +127,12 @@ public struct File {
channels = file?["channels"] as? [String]
groups = file?["groups"] as? [String]
ims = file?["ims"] as? [String]
initialComment = Comment(comment: file?["initial_comment"] as? [String: Any])
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? [Any] {
self.reactions = Reaction.reactionsFromArray(array: reactions)
if let reactions = file?["reactions"] as? [[String: AnyObject]] {
self.reactions = Reaction.reactionsFromArray(reactions)
}
}
@@ -126,6 +158,22 @@ public struct File {
thumb360gif = nil
thumb360w = nil
thumb360h = nil
thumb480 = nil
thumb480gif = nil
thumb480w = nil
thumb480h = nil
thumb720 = nil
thumb720gif = nil
thumb720w = nil
thumb720h = nil
thumb960 = nil
thumb960gif = nil
thumb960w = nil
thumb960h = nil
thumb1024 = nil
thumb1024gif = nil
thumb1024w = nil
thumb1024h = nil
permalink = nil
editLink = nil
preview = nil
+9 -9
View File
@@ -32,7 +32,7 @@ public class Message {
internal(set) public var text: String?
public let botID: String?
public let username: String?
public let icons: [String: Any]?
public let icons: [String: AnyObject]?
public let deletedTs: String?
internal(set) var purpose: String?
internal(set) var topic: String?
@@ -48,7 +48,7 @@ public class Message {
internal(set) public var reactions = [String: Reaction]()
internal(set) public var attachments: [Attachment]?
public init?(message: [String: Any]?) {
public init?(message: [String: AnyObject]?) {
subtype = message?["subtype"] as? String
ts = message?["ts"] as? String
user = message?["user"] as? String
@@ -57,7 +57,7 @@ public class Message {
text = message?["text"] as? String
botID = message?["bot_id"] as? String
username = message?["username"] as? String
icons = message?["icons"] as? [String: Any]
icons = message?["icons"] as? [String: AnyObject]
deletedTs = message?["deleted_ts"] as? String
purpose = message?["purpose"] as? String
topic = message?["topic"] as? String
@@ -68,10 +68,10 @@ 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? [String: Any])
file = File(file: message?["file"] as? [String: Any])
reactions = messageReactions(reactions: message?["reactions"] as? [Any])
attachments = (message?["attachments"] as? [Any])?.objectArrayFromDictionaryArray(intializer: {(attachment) -> Attachment? in
comment = Comment(comment: message?["comment"] as? [String: AnyObject])
file = File(file: message?["file"] as? [String: AnyObject])
reactions = messageReactions(message?["reactions"] as? [[String: AnyObject]])
attachments = (message?["attachments"] as? [[String: AnyObject]])?.objectArrayFromDictionaryArray({(attachment) -> Attachment? in
return Attachment(attachment: attachment)
})
}
@@ -91,11 +91,11 @@ public class Message {
file = nil
}
private func messageReactions(reactions: [Any]?) -> [String: Reaction] {
private func messageReactions(reactions: [[String: AnyObject]]?) -> [String: Reaction] {
var returnValue = [String: Reaction]()
if let r = reactions {
for react in r {
if let reaction = Reaction(reaction: react as? [String: Any]), reactionName = reaction.name {
if let reaction = Reaction(reaction: react), reactionName = reaction.name {
returnValue[reactionName] = reaction
}
}
+65 -88
View File
@@ -21,131 +21,108 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import C7
import HTTPSClient
import Jay
import WebSocketClient
import Foundation
internal struct NetworkInterface {
private let apiUrl = "https://slack.com/api/"
private let client: HTTPSClient.Client?
init() {
do {
self.client = try Client(uri: URI("https://slack.com"))
} catch {
self.client = nil
}
}
internal func request(endpoint: SlackAPIEndpoint, token: String, parameters: [String: Any]?, successClosure: ([String: Any])->Void, errorClosure: (SlackError)->Void) {
internal func request(endpoint: SlackAPIEndpoint, token: String, parameters: [String: AnyObject]?, successClosure: ([String: AnyObject])->Void, errorClosure: (SlackError)->Void) {
var requestString = "\(apiUrl)\(endpoint.rawValue)?token=\(token)"
if let params = parameters {
requestString += requestStringFromParameters(parameters: params)
requestString += requestStringFromParameters(params)
}
do {
var response: Response?
response = try client?.get(requestString)
let data = try response?.body.becomeBuffer()
if let data = data {
let json = try Jay().jsonFromData(data.bytes)
if let result = json as? [String: Any] {
if (result["ok"] as? Bool == true) {
successClosure(result)
let request = NSURLRequest(URL: NSURL(string: requestString)!)
NSURLSession.sharedSession().dataTaskWithRequest(request) {
(data, response, internalError) -> Void in
guard let data = data else {
errorClosure(SlackError.ClientNetworkError)
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject]
if (result["ok"] as! Bool == true) {
successClosure(result)
} else {
if let errorString = result["error"] as? String {
throw ErrorDispatcher.dispatch(errorString)
} else {
if let errorString = result["error"] as? String {
throw ErrorDispatcher.dispatch(error: errorString)
} else {
throw SlackError.UnknownError
}
throw SlackError.UnknownError
}
}
} catch let error {
if let slackError = error as? SlackError {
errorClosure(slackError)
} else {
errorClosure(SlackError.UnknownError)
}
}
} catch let error {
if let slackError = error as? SlackError {
errorClosure(slackError)
} else {
errorClosure(SlackError.UnknownError)
}
}
}.resume()
}
internal func uploadRequest(token: String, data: Data, parameters: [String: Any]?, successClosure: ([String: Any])->Void, errorClosure: (SlackError)->Void) {
internal func uploadRequest(token: String, data: NSData, parameters: [String: AnyObject]?, successClosure: ([String: AnyObject])->Void, errorClosure: (SlackError)->Void) {
var requestString = "\(apiUrl)\(SlackAPIEndpoint.FilesUpload.rawValue)?token=\(token)"
if let params = parameters {
requestString = requestString + requestStringFromParameters(parameters: params)
requestString = requestString + requestStringFromParameters(params)
}
let request = NSMutableURLRequest(URL: NSURL(string: requestString)!)
request.HTTPMethod = "POST"
let boundaryConstant = randomBoundary()
let contentType = "multipart/form-data; boundary=" + boundaryConstant
let boundaryStart = "--\(boundaryConstant)\r\n"
let boundaryEnd = "--\(boundaryConstant)--\r\n"
let contentDispositionString = "Content-Disposition: form-data; name=\"file\"; filename=\"\(parameters!["filename"])\"\r\n"
let contentTypeString = "Content-Type: \(parameters!["filetype"])\r\n\r\n"
var requestBodyData = Data()
requestBodyData.append(contentsOf: boundaryStart.data.bytes)
requestBodyData.append(contentsOf: contentDispositionString.data.bytes)
requestBodyData.append(contentsOf: contentTypeString.data.bytes)
requestBodyData.append(contentsOf: data)
requestBodyData.append(contentsOf: "\r\n".data.bytes)
requestBodyData.append(contentsOf: boundaryEnd.data.bytes)
let requestBodyData : NSMutableData = NSMutableData()
requestBodyData.appendData(boundaryStart.dataUsingEncoding(NSUTF8StringEncoding)!)
requestBodyData.appendData(contentDispositionString.dataUsingEncoding(NSUTF8StringEncoding)!)
requestBodyData.appendData(contentTypeString.dataUsingEncoding(NSUTF8StringEncoding)!)
requestBodyData.appendData(data)
requestBodyData.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
requestBodyData.appendData(boundaryEnd.dataUsingEncoding(NSUTF8StringEncoding)!)
let header: Headers = ["Content-Type":"multipart/form-data; boundary=" + boundaryConstant]
do {
var response: Response?
response = try client?.post(requestString, headers: header, body: requestBodyData)
let data = try response?.body.becomeBuffer()
if let data = data {
let json = try Jay().jsonFromData(data.bytes)
if let result = json as? [String: Any] {
if (result["ok"] as? Bool == true) {
successClosure(result)
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.HTTPBody = requestBodyData
NSURLSession.sharedSession().dataTaskWithRequest(request) {
(data, response, internalError) -> Void in
guard let data = data else {
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String: AnyObject]
if (result["ok"] as! Bool == true) {
successClosure(result)
} else {
if let errorString = result["error"] as? String {
throw ErrorDispatcher.dispatch(errorString)
} else {
if let errorString = result["error"] as? String {
throw ErrorDispatcher.dispatch(error: errorString)
} else {
throw SlackError.UnknownError
}
throw SlackError.UnknownError
}
}
} catch let error {
if let slackError = error as? SlackError {
errorClosure(slackError)
} else {
errorClosure(SlackError.UnknownError)
}
}
} catch let error {
if let slackError = error as? SlackError {
errorClosure(slackError)
} else {
errorClosure(SlackError.UnknownError)
}
}
}.resume()
}
private func randomBoundary() -> String {
#if os(Linux)
return "slackkit.boundary.\(Int(random()))\(Int(random()))"
#else
return "slackkit.boundary.\(arc4random())\(arc4random())"
#endif
return String(format: "slackkit.boundary.%08x%08x", arc4random(), arc4random())
}
private func requestStringFromParameters(parameters: [String: Any]) -> String {
private func requestStringFromParameters(parameters: [String: AnyObject]) -> String {
var requestString = ""
for key in parameters.keys {
if let value = parameters[key] as? String {
do {
let encodedValue = try value.percentEncoded(allowing: .uriQueryAllowed)
requestString += "&\(key)=\(encodedValue)"
} catch _ {
print("Error encoding parameters.")
}
if let value = parameters[key] as? String, encodedValue = value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet()) {
requestString += "&\(key)=\(encodedValue)"
} else if let value = parameters[key] as? Int {
requestString += "&\(key)=\(value)"
} else if let value = parameters[key] as? Bool {
requestString += "&\(key)=\(value)"
}
}
+142 -130
View File
@@ -21,8 +21,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import C7
import Jay
import Foundation
internal enum SlackAPIEndpoint: String {
case APITest = "api.test"
@@ -43,6 +42,7 @@ internal enum SlackAPIEndpoint: String {
case FilesCommentsEdit = "files.comments.edit"
case FilesCommentsDelete = "files.comments.delete"
case FilesDelete = "files.delete"
case FilesInfo = "files.info"
case FilesUpload = "files.upload"
case GroupsClose = "groups.close"
case GroupsHistory = "groups.history"
@@ -104,22 +104,16 @@ public class SlackWebAPI {
case IM = "im"
}
private let networkInterface: NetworkInterface
private let token: String
private let client: Client
init(networkInterface: NetworkInterface, token: String) {
self.networkInterface = networkInterface
self.token = token
}
convenience public init(slackClient: SlackClient) {
self.init(networkInterface: slackClient.api, token: slackClient.token)
required public init(client: Client) {
self.client = client
}
//MARK: - RTM
public func rtmStart(simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, success: ((response: [String: Any])->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["simple_latest": simpleLatest, "no_unreads": noUnreads, "mpim_aware": mpimAware]
networkInterface.request(endpoint: .RTMStart, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
public func rtmStart(simpleLatest: Bool? = nil, noUnreads: Bool? = nil, mpimAware: Bool? = nil, success: ((response: [String: AnyObject])->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject?] = ["simple_latest": simpleLatest, "no_unreads": noUnreads, "mpim_aware": mpimAware]
client.api.request(.RTMStart, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(response: response)
}) {(error) -> Void in
@@ -129,7 +123,7 @@ public class SlackWebAPI {
//MARK: - Auth Test
public func authenticationTest(success: ((authenticated: Bool)->Void)?, failure: FailureClosure?) {
networkInterface.request(endpoint: .AuthTest, token: token, parameters: nil, successClosure: {
client.api.request(.AuthTest, token: client.token, parameters: nil, successClosure: {
(response) -> Void in
success?(authenticated: true)
}) {(error) -> Void in
@@ -138,8 +132,8 @@ public class SlackWebAPI {
}
//MARK: - Channels
public func channelHistory(id: String, latest: String = "\(Time.slackTimestamp())", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(endpoint: .ChannelsHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
public func channelHistory(id: String, latest: String = "\(NSDate().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(.ChannelsHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
(history) -> Void in
success?(history: history)
}) {(error) -> Void in
@@ -148,7 +142,7 @@ public class SlackWebAPI {
}
public func channelInfo(id: String, success: ((channel: Channel?)->Void)?, failure: FailureClosure?) {
info(endpoint: .ChannelsInfo, type:ChannelType.Channel, id: id, success: {
info(.ChannelsInfo, type:ChannelType.Channel, id: id, success: {
(channel) -> Void in
success?(channel: channel)
}) { (error) -> Void in
@@ -156,8 +150,8 @@ public class SlackWebAPI {
}
}
public func channelsList(excludeArchived: Bool = false, success: ((channels: [Any]?)->Void)?, failure: FailureClosure?) {
list(endpoint: .ChannelsList, type:ChannelType.Channel, excludeArchived: excludeArchived, success: {
public func channelsList(excludeArchived: Bool = false, success: ((channels: [[String: AnyObject]]?)->Void)?, failure: FailureClosure?) {
list(.ChannelsList, type:ChannelType.Channel, excludeArchived: excludeArchived, success: {
(channels) -> Void in
success?(channels: channels)
}) {(error) -> Void in
@@ -166,7 +160,7 @@ public class SlackWebAPI {
}
public func markChannel(channel: String, timestamp: String, success: ((ts: String)->Void)?, failure: FailureClosure?) {
mark(endpoint: .ChannelsMark, channel: channel, timestamp: timestamp, success: {
mark(.ChannelsMark, channel: channel, timestamp: timestamp, success: {
(ts) -> Void in
success?(ts:timestamp)
}) {(error) -> Void in
@@ -175,7 +169,7 @@ public class SlackWebAPI {
}
public func setChannelPurpose(channel: String, purpose: String, success: ((purposeSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(endpoint: .ChannelsSetPurpose, type: .Purpose, channel: channel, text: purpose, success: {
setInfo(.ChannelsSetPurpose, type: .Purpose, channel: channel, text: purpose, success: {
(purposeSet) -> Void in
success?(purposeSet: purposeSet)
}) { (error) -> Void in
@@ -184,7 +178,7 @@ public class SlackWebAPI {
}
public func setChannelTopic(channel: String, topic: String, success: ((topicSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(endpoint: .ChannelsSetTopic, type: .Topic, channel: channel, text: topic, success: {
setInfo(.ChannelsSetTopic, type: .Topic, channel: channel, text: topic, success: {
(topicSet) -> Void in
success?(topicSet: topicSet)
}) {(error) -> Void in
@@ -194,8 +188,8 @@ public class SlackWebAPI {
//MARK: - Messaging
public func deleteMessage(channel: String, ts: String, success: ((deleted: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": channel, "ts": ts]
networkInterface.request(endpoint: .ChatDelete, token: token, parameters: parameters, successClosure: { (response) -> Void in
let parameters: [String: AnyObject] = ["channel": channel, "ts": ts]
client.api.request(.ChatDelete, token: client.token, parameters: parameters, successClosure: { (response) -> Void in
success?(deleted: true)
}) {(error) -> Void in
failure?(error: error)
@@ -203,8 +197,8 @@ public class SlackWebAPI {
}
public func sendMessage(channel: String, text: String, username: String? = nil, asUser: Bool? = nil, parse: ParseMode? = nil, linkNames: Bool? = nil, attachments: [Attachment?]? = nil, unfurlLinks: Bool? = nil, unfurlMedia: Bool? = nil, iconURL: String? = nil, iconEmoji: String? = nil, success: (((ts: String?, channel: String?))->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel":channel, "text":text.slackFormatEscaping(), "as_user":asUser, "parse":parse?.rawValue, "link_names":linkNames, "unfurl_links":unfurlLinks, "unfurlMedia":unfurlMedia, "username":username, "attachments":encodeAttachments(attachments: attachments), "icon_url":iconURL, "icon_emoji":iconEmoji]
networkInterface.request(endpoint: .ChatPostMessage, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
let parameters: [String: AnyObject?] = ["channel":channel, "text":text.slackFormatEscaping(), "as_user":asUser, "parse":parse?.rawValue, "link_names":linkNames, "unfurl_links":unfurlLinks, "unfurlMedia":unfurlMedia, "username":username, "attachments":encodeAttachments(attachments), "icon_url":iconURL, "icon_emoji":iconEmoji]
client.api.request(.ChatPostMessage, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?((ts: response["ts"] as? String, response["channel"] as? String))
}) {(error) -> Void in
@@ -213,8 +207,8 @@ public class SlackWebAPI {
}
public func updateMessage(channel: String, ts: String, message: String, attachments: [Attachment?]? = nil, parse:ParseMode = .None, linkNames: Bool = false, success: ((updated: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel": channel, "ts": ts, "text": message.slackFormatEscaping(), "parse": parse.rawValue, "link_names": linkNames, "attachments":encodeAttachments(attachments: attachments)]
networkInterface.request(endpoint: .ChatUpdate, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
let parameters: [String: AnyObject?] = ["channel": channel, "ts": ts, "text": message.slackFormatEscaping(), "parse": parse.rawValue, "link_names": linkNames, "attachments":encodeAttachments(attachments)]
client.api.request(.ChatUpdate, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(updated: true)
}) {(error) -> Void in
@@ -224,8 +218,8 @@ public class SlackWebAPI {
//MARK: - Do Not Disturb
public func dndInfo(user: String? = nil, success: ((status: DoNotDisturbStatus?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["user": user]
networkInterface.request(endpoint: .DNDInfo, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
let parameters: [String: AnyObject?] = ["user": user]
client.api.request(.DNDInfo, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(status: DoNotDisturbStatus(status: response))
}) {(error) -> Void in
@@ -234,20 +228,20 @@ public class SlackWebAPI {
}
public func dndTeamInfo(users: [String]? = nil, success: ((statuses: [String: DoNotDisturbStatus]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["users":users?.joined(separator: ",")]
networkInterface.request(endpoint: .DNDTeamInfo, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
let parameters: [String: AnyObject?] = ["users":users?.joinWithSeparator(",")]
client.api.request(.DNDTeamInfo, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(statuses: self.enumerateDNDStauses(statuses: response["users"] as? [String: Any]))
success?(statuses: self.enumerateDNDStauses(response["users"] as? [String: AnyObject]))
}) {(error) -> Void in
failure?(error: error)
}
}
//MARK: - Emoji
public func emojiList(success: ((emojiList: [String: Any]?)->Void)?, failure: FailureClosure?) {
networkInterface.request(endpoint: .EmojiList, token: token, parameters: nil, successClosure: {
public func emojiList(success: ((emojiList: [String: AnyObject]?)->Void)?, failure: FailureClosure?) {
client.api.request(.EmojiList, token: client.token, parameters: nil, successClosure: {
(response) -> Void in
success?(emojiList: response["emoji"] as? [String: Any])
success?(emojiList: response["emoji"] as? [String: AnyObject])
}) { (error) -> Void in
failure?(error: error)
}
@@ -255,8 +249,8 @@ public class SlackWebAPI {
//MARK: - Files
public func deleteFile(fileID: String, success: ((deleted: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file":fileID]
networkInterface.request(endpoint: .FilesDelete, token: token, parameters: parameters, successClosure: {
let parameters = ["file":fileID]
client.api.request(.FilesDelete, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(deleted: true)
}) {(error) -> Void in
@@ -264,11 +258,28 @@ public class SlackWebAPI {
}
}
public func uploadFile(file: Data, filename: String, filetype: String = "auto", title: String? = nil, initialComment: String? = nil, channels: [String]? = nil, success: ((file: File?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["file":file, "filename": filename, "filetype":filetype, "title":title, "initial_comment":initialComment, "channels":channels?.joined(separator: ",")]
networkInterface.uploadRequest(token: token, data: file, parameters: filterNilParameters(parameters: parameters), successClosure: {
public func fileInfo(fileID: String, commentCount: Int = 100, totalPages: Int = 1, success: ((file: File?)->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject] = ["file":fileID, "count": commentCount, "totalPages":totalPages]
client.api.request(.FilesInfo, token: client.token, parameters: parameters, successClosure: {
(response) in
var file = File(file: response["file"] as? [String: AnyObject])
(response["comments"] as? [[String: AnyObject]])?.objectArrayFromDictionaryArray({(comment) -> Comment? in
if let comment = Comment(comment: comment), id = comment.id {
file?.comments[id] = comment
}
return nil
})
success?(file: file)
}) {(error) in
failure?(error: error)
}
}
public func uploadFile(file: NSData, filename: String, filetype: String = "auto", title: String? = nil, initialComment: String? = nil, channels: [String]? = nil, success: ((file: File?)->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject?] = ["file":file, "filename": filename, "filetype":filetype, "title":title, "initial_comment":initialComment, "channels":channels?.joinWithSeparator(",")]
client.api.uploadRequest(client.token, data: file, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(file: File(file: response["file"] as? [String: Any]))
success?(file: File(file: response["file"] as? [String: AnyObject]))
}) {(error) -> Void in
failure?(error: error)
}
@@ -276,28 +287,28 @@ public class SlackWebAPI {
//MARK: - File Comments
public func addFileComment(fileID: String, comment: String, success: ((comment: Comment?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file":fileID, "comment":comment.slackFormatEscaping()]
networkInterface.request(endpoint: .FilesCommentsAdd, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["file":fileID, "comment":comment.slackFormatEscaping()]
client.api.request(.FilesCommentsAdd, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(comment: Comment(comment: response["comment"] as? [String: Any]))
success?(comment: Comment(comment: response["comment"] as? [String: AnyObject]))
}) {(error) -> Void in
failure?(error: error)
}
}
public func editFileComment(fileID: String, commentID: String, comment: String, success: ((comment: Comment?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file":fileID, "id":commentID, "comment":comment.slackFormatEscaping()]
networkInterface.request(endpoint: .FilesCommentsEdit, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["file":fileID, "id":commentID, "comment":comment.slackFormatEscaping()]
client.api.request(.FilesCommentsEdit, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(comment: Comment(comment: response["comment"] as? [String: Any]))
success?(comment: Comment(comment: response["comment"] as? [String: AnyObject]))
}) {(error) -> Void in
failure?(error: error)
}
}
public func deleteFileComment(fileID: String, commentID: String, success: ((deleted: Bool?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["file":fileID, "id": commentID]
networkInterface.request(endpoint: .FilesCommentsDelete, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["file":fileID, "id": commentID]
client.api.request(.FilesCommentsDelete, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(deleted: true)
}) {(error) -> Void in
@@ -307,7 +318,7 @@ public class SlackWebAPI {
//MARK: - Groups
public func closeGroup(groupID: String, success: ((closed: Bool)->Void)?, failure: FailureClosure?) {
close(endpoint: .GroupsClose, channelID: groupID, success: {
close(.GroupsClose, channelID: groupID, success: {
(closed) -> Void in
success?(closed:closed)
}) {(error) -> Void in
@@ -315,8 +326,8 @@ public class SlackWebAPI {
}
}
public func groupHistory(id: String, latest: String = "\(Time.slackTimestamp())", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(endpoint: .GroupsHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
public func groupHistory(id: String, latest: String = "\(NSDate().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(.GroupsHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
(history) -> Void in
success?(history: history)
}) {(error) -> Void in
@@ -325,7 +336,7 @@ public class SlackWebAPI {
}
public func groupInfo(id: String, success: ((channel: Channel?)->Void)?, failure: FailureClosure?) {
info(endpoint: .GroupsInfo, type:ChannelType.Group, id: id, success: {
info(.GroupsInfo, type:ChannelType.Group, id: id, success: {
(channel) -> Void in
success?(channel: channel)
}) {(error) -> Void in
@@ -333,8 +344,8 @@ public class SlackWebAPI {
}
}
public func groupsList(excludeArchived: Bool = false, success: ((channels: [Any]?)->Void)?, failure: FailureClosure?) {
list(endpoint: .GroupsList, type:ChannelType.Group, excludeArchived: excludeArchived, success: {
public func groupsList(excludeArchived: Bool = false, success: ((channels: [[String: AnyObject]]?)->Void)?, failure: FailureClosure?) {
list(.GroupsList, type:ChannelType.Group, excludeArchived: excludeArchived, success: {
(channels) -> Void in
success?(channels: channels)
}) {(error) -> Void in
@@ -343,7 +354,7 @@ public class SlackWebAPI {
}
public func markGroup(channel: String, timestamp: String, success: ((ts: String)->Void)?, failure: FailureClosure?) {
mark(endpoint: .GroupsMark, channel: channel, timestamp: timestamp, success: {
mark(.GroupsMark, channel: channel, timestamp: timestamp, success: {
(ts) -> Void in
success?(ts: timestamp)
}) {(error) -> Void in
@@ -352,8 +363,8 @@ public class SlackWebAPI {
}
public func openGroup(channel: String, success: ((opened: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel":channel]
networkInterface.request(endpoint: .GroupsOpen, token: token, parameters: parameters, successClosure: {
let parameters = ["channel":channel]
client.api.request(.GroupsOpen, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(opened: true)
}) {(error) -> Void in
@@ -362,7 +373,7 @@ public class SlackWebAPI {
}
public func setGroupPurpose(channel: String, purpose: String, success: ((purposeSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(endpoint: .GroupsSetPurpose, type: .Purpose, channel: channel, text: purpose, success: {
setInfo(.GroupsSetPurpose, type: .Purpose, channel: channel, text: purpose, success: {
(purposeSet) -> Void in
success?(purposeSet: purposeSet)
}) {(error) -> Void in
@@ -371,7 +382,7 @@ public class SlackWebAPI {
}
public func setGroupTopic(channel: String, topic: String, success: ((topicSet: Bool)->Void)?, failure: FailureClosure?) {
setInfo(endpoint: .GroupsSetTopic, type: .Topic, channel: channel, text: topic, success: {
setInfo(.GroupsSetTopic, type: .Topic, channel: channel, text: topic, success: {
(topicSet) -> Void in
success?(topicSet: topicSet)
}) {(error) -> Void in
@@ -381,7 +392,7 @@ public class SlackWebAPI {
//MARK: - IM
public func closeIM(channel: String, success: ((closed: Bool)->Void)?, failure: FailureClosure?) {
close(endpoint: .IMClose, channelID: channel, success: {
close(.IMClose, channelID: channel, success: {
(closed) -> Void in
success?(closed: closed)
}) {(error) -> Void in
@@ -389,8 +400,8 @@ public class SlackWebAPI {
}
}
public func imHistory(id: String, latest: String = "\(Time.slackTimestamp())", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(endpoint: .IMHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
public func imHistory(id: String, latest: String = "\(NSDate().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(.IMHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
(history) -> Void in
success?(history: history)
}) {(error) -> Void in
@@ -398,8 +409,8 @@ public class SlackWebAPI {
}
}
public func imsList(excludeArchived: Bool = false, success: ((channels: [Any]?)->Void)?, failure: FailureClosure?) {
list(endpoint: .IMList, type:ChannelType.IM, excludeArchived: excludeArchived, success: {
public func imsList(excludeArchived: Bool = false, success: ((channels: [[String: AnyObject]]?)->Void)?, failure: FailureClosure?) {
list(.IMList, type:ChannelType.IM, excludeArchived: excludeArchived, success: {
(channels) -> Void in
success?(channels: channels)
}) {(error) -> Void in
@@ -408,7 +419,7 @@ public class SlackWebAPI {
}
public func markIM(channel: String, timestamp: String, success: ((ts: String)->Void)?, failure: FailureClosure?) {
mark(endpoint: .IMMark, channel: channel, timestamp: timestamp, success: {
mark(.IMMark, channel: channel, timestamp: timestamp, success: {
(ts) -> Void in
success?(ts: timestamp)
}) {(error) -> Void in
@@ -417,10 +428,10 @@ public class SlackWebAPI {
}
public func openIM(userID: String, success: ((imID: String?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["user":userID]
networkInterface.request(endpoint: .IMOpen, token: token, parameters: parameters, successClosure: {
let parameters = ["user":userID]
client.api.request(.IMOpen, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
let group = response["channel"] as? [String: Any]
let group = response["channel"] as? [String: AnyObject]
success?(imID: group?["id"] as? String)
}) {(error) -> Void in
failure?(error: error)
@@ -429,7 +440,7 @@ public class SlackWebAPI {
//MARK: - MPIM
public func closeMPIM(channel: String, success: ((closed: Bool)->Void)?, failure: FailureClosure?) {
close(endpoint: .MPIMClose, channelID: channel, success: {
close(.MPIMClose, channelID: channel, success: {
(closed) -> Void in
success?(closed: closed)
}) {(error) -> Void in
@@ -437,8 +448,8 @@ public class SlackWebAPI {
}
}
public func mpimHistory(id: String, latest: String = "\(Time.slackTimestamp())", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(endpoint: .MPIMHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
public func mpimHistory(id: String, latest: String = "\(NSDate().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
history(.MPIMHistory, id: id, latest: latest, oldest: oldest, inclusive: inclusive, count: count, unreads: unreads, success: {
(history) -> Void in
success?(history: history)
}) {(error) -> Void in
@@ -446,8 +457,8 @@ public class SlackWebAPI {
}
}
public func mpimsList(excludeArchived: Bool = false, success: ((channels: [Any]?)->Void)?, failure: FailureClosure?) {
list(endpoint: .MPIMList, type:ChannelType.Group, excludeArchived: excludeArchived, success: {
public func mpimsList(excludeArchived: Bool = false, success: ((channels: [[String: AnyObject]]?)->Void)?, failure: FailureClosure?) {
list(.MPIMList, type:ChannelType.Group, excludeArchived: excludeArchived, success: {
(channels) -> Void in
success?(channels: channels)
}) {(error) -> Void in
@@ -456,7 +467,7 @@ public class SlackWebAPI {
}
public func markMPIM(channel: String, timestamp: String, success: ((ts: String)->Void)?, failure: FailureClosure?) {
mark(endpoint: .MPIMMark, channel: channel, timestamp: timestamp, success: {
mark(.MPIMMark, channel: channel, timestamp: timestamp, success: {
(ts) -> Void in
success?(ts: timestamp)
}) {(error) -> Void in
@@ -465,10 +476,10 @@ public class SlackWebAPI {
}
public func openMPIM(userIDs: [String], success: ((mpimID: String?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["users":userIDs.joined(separator: ",")]
networkInterface.request(endpoint: .MPIMOpen, token: token, parameters: parameters, successClosure: {
let parameters = ["users":userIDs.joinWithSeparator(",")]
client.api.request(.MPIMOpen, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
let group = response["group"] as? [String: Any]
let group = response["group"] as? [String: AnyObject]
success?(mpimID: group?["id"] as? String)
}) {(error) -> Void in
failure?(error: error)
@@ -477,7 +488,7 @@ public class SlackWebAPI {
//MARK: - Pins
public func pinItem(channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((pinned: Bool)->Void)?, failure: FailureClosure?) {
pin(endpoint: .PinsAdd, channel: channel, file: file, fileComment: fileComment, timestamp: timestamp, success: {
pin(.PinsAdd, channel: channel, file: file, fileComment: fileComment, timestamp: timestamp, success: {
(ok) -> Void in
success?(pinned: ok)
}) {(error) -> Void in
@@ -486,7 +497,7 @@ public class SlackWebAPI {
}
public func unpinItem(channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((unpinned: Bool)->Void)?, failure: FailureClosure?) {
pin(endpoint: .PinsRemove, channel: channel, file: file, fileComment: fileComment, timestamp: timestamp, success: {
pin(.PinsRemove, channel: channel, file: file, fileComment: fileComment, timestamp: timestamp, success: {
(ok) -> Void in
success?(unpinned: ok)
}) {(error) -> Void in
@@ -495,8 +506,8 @@ public class SlackWebAPI {
}
private func pin(endpoint: SlackAPIEndpoint, channel: String, file: String? = nil, fileComment: String? = nil, timestamp: String? = nil, success: ((ok: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["channel":channel, "file":file, "file_comment":fileComment, "timestamp":timestamp]
networkInterface.request(endpoint: endpoint, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
let parameters: [String: AnyObject?] = ["channel":channel, "file":file, "file_comment":fileComment, "timestamp":timestamp]
client.api.request(endpoint, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(ok: true)
}){(error) -> Void in
@@ -507,7 +518,7 @@ public class SlackWebAPI {
//MARK: - Reactions
// One of file, file_comment, or the combination of channel and timestamp must be specified.
public func addReaction(name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((reacted: Bool)->Void)?, failure: FailureClosure?) {
react(endpoint: .ReactionsAdd, name: name, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
react(.ReactionsAdd, name: name, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
(ok) -> Void in
success?(reacted: ok)
}) {(error) -> Void in
@@ -517,7 +528,7 @@ public class SlackWebAPI {
// One of file, file_comment, or the combination of channel and timestamp must be specified.
public func removeReaction(name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((unreacted: Bool)->Void)?, failure: FailureClosure?) {
react(endpoint: .ReactionsRemove, name: name, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
react(.ReactionsRemove, name: name, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
(ok) -> Void in
success?(unreacted: ok)
}) {(error) -> Void in
@@ -526,8 +537,8 @@ public class SlackWebAPI {
}
private func react(endpoint: SlackAPIEndpoint, name: String, file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((ok: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["name":name, "file":file, "file_comment":fileComment, "channel":channel, "timestamp":timestamp]
networkInterface.request(endpoint: endpoint, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
let parameters: [String: AnyObject?] = ["name":name, "file":file, "file_comment":fileComment, "channel":channel, "timestamp":timestamp]
client.api.request(endpoint, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(ok: true)
}) {(error) -> Void in
@@ -538,7 +549,7 @@ public class SlackWebAPI {
//MARK: - Stars
// One of file, file_comment, channel, or the combination of channel and timestamp must be specified.
public func addStar(file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((starred: Bool)->Void)?, failure: FailureClosure?) {
star(endpoint: .StarsAdd, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
star(.StarsAdd, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
(ok) -> Void in
success?(starred: ok)
}) {(error) -> Void in
@@ -548,7 +559,7 @@ public class SlackWebAPI {
// One of file, file_comment, channel, or the combination of channel and timestamp must be specified.
public func removeStar(file: String? = nil, fileComment: String? = nil, channel: String? = nil, timestamp: String? = nil, success: ((unstarred: Bool)->Void)?, failure: FailureClosure?) {
star(endpoint: .StarsRemove, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
star(.StarsRemove, file: file, fileComment: fileComment, channel: channel, timestamp: timestamp, success: {
(ok) -> Void in
success?(unstarred: ok)
}) {(error) -> Void in
@@ -557,8 +568,8 @@ public class SlackWebAPI {
}
private func star(endpoint: SlackAPIEndpoint, file: String?, fileComment: String?, channel: String?, timestamp: String?, success: ((ok: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any?] = ["file":file, "file_comment":fileComment, "channel":channel, "timestamp":timestamp]
networkInterface.request(endpoint: endpoint, token: token, parameters: filterNilParameters(parameters: parameters), successClosure: {
let parameters: [String: AnyObject?] = ["file":file, "file_comment":fileComment, "channel":channel, "timestamp":timestamp]
client.api.request(endpoint, token: client.token, parameters: filterNilParameters(parameters), successClosure: {
(response) -> Void in
success?(ok: true)
}) {(error) -> Void in
@@ -568,10 +579,10 @@ public class SlackWebAPI {
//MARK: - Team
public func teamInfo(success: ((info: [String: Any]?)->Void)?, failure: FailureClosure?) {
networkInterface.request(endpoint: .TeamInfo, token: token, parameters: nil, successClosure: {
public func teamInfo(success: ((info: [String: AnyObject]?)->Void)?, failure: FailureClosure?) {
client.api.request(.TeamInfo, token: client.token, parameters: nil, successClosure: {
(response) -> Void in
success?(info: response["team"] as? [String: Any])
success?(info: response["team"] as? [String: AnyObject])
}) {(error) -> Void in
failure?(error: error)
}
@@ -579,8 +590,8 @@ public class SlackWebAPI {
//MARK: - Users
public func userPresence(user: String, success: ((presence: String?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["user":user]
networkInterface.request(endpoint: .UsersGetPresence, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["user":user]
client.api.request(.UsersGetPresence, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(presence: response["presence"] as? String)
}){(error) -> Void in
@@ -589,27 +600,27 @@ public class SlackWebAPI {
}
public func userInfo(id: String, success: ((user: User?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["user":id]
networkInterface.request(endpoint: .UsersInfo, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["user":id]
client.api.request(.UsersInfo, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(user: User(user: response["user"] as? [String: Any]))
success?(user: User(user: response["user"] as? [String: AnyObject]))
}) {(error) -> Void in
failure?(error: error)
}
}
public func usersList(includePresence: Bool = false, success: ((userList: [String: Any]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["presence":includePresence]
networkInterface.request(endpoint: .UsersList, token: token, parameters: parameters, successClosure: {
public func usersList(includePresence: Bool = false, success: ((userList: [[String: AnyObject]]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject] = ["presence":includePresence]
client.api.request(.UsersList, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(userList: response["members"] as? [String: Any])
success?(userList: response["members"] as? [[String: AnyObject]])
}){(error) -> Void in
failure?(error: error)
}
}
public func setUserActive(success: ((success: Bool)->Void)?, failure: FailureClosure?) {
networkInterface.request(endpoint: .UsersSetActive, token: token, parameters: nil, successClosure: {
client.api.request(.UsersSetActive, token: client.token, parameters: nil, successClosure: {
(response) -> Void in
success?(success: true)
}) {(error) -> Void in
@@ -618,8 +629,8 @@ public class SlackWebAPI {
}
public func setUserPresence(presence: Presence, success: ((success: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["presence":presence.rawValue]
networkInterface.request(endpoint: .UsersSetPresence, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["presence":presence.rawValue]
client.api.request(.UsersSetPresence, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(success:true)
}) {(error) -> Void in
@@ -629,8 +640,8 @@ public class SlackWebAPI {
//MARK: - Channel Utilities
private func close(endpoint: SlackAPIEndpoint, channelID: String, success: ((closed: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel":channelID]
networkInterface.request(endpoint: endpoint, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["channel":channelID]
client.api.request(endpoint, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(closed: true)
}) {(error) -> Void in
@@ -638,9 +649,9 @@ public class SlackWebAPI {
}
}
private func history(endpoint: SlackAPIEndpoint, id: String, latest: String = "\(Time.slackTimestamp())", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": id, "latest": latest, "oldest": oldest, "inclusive":inclusive, "count":count, "unreads":unreads]
networkInterface.request(endpoint: endpoint, token: token, parameters: parameters, successClosure: {
private func history(endpoint: SlackAPIEndpoint, id: String, latest: String = "\(NSDate().timeIntervalSince1970)", oldest: String = "0", inclusive: Bool = false, count: Int = 100, unreads: Bool = false, success: ((history: History?)->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject] = ["channel": id, "latest": latest, "oldest": oldest, "inclusive":inclusive, "count":count, "unreads":unreads]
client.api.request(endpoint, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(history: History(history: response))
}) {(error) -> Void in
@@ -649,28 +660,28 @@ public class SlackWebAPI {
}
private func info(endpoint: SlackAPIEndpoint, type: ChannelType, id: String, success: ((channel: Channel?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": id]
networkInterface.request(endpoint: endpoint, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["channel": id]
client.api.request(endpoint, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(channel: Channel(channel: response[type.rawValue] as? [String: Any]))
success?(channel: Channel(channel: response[type.rawValue] as? [String: AnyObject]))
}) {(error) -> Void in
failure?(error: error)
}
}
private func list(endpoint: SlackAPIEndpoint, type: ChannelType, excludeArchived: Bool = false, success: ((channels: [Any]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["exclude_archived": excludeArchived]
networkInterface.request(endpoint: endpoint, token: token, parameters: parameters, successClosure: {
private func list(endpoint: SlackAPIEndpoint, type: ChannelType, excludeArchived: Bool = false, success: ((channels: [[String: AnyObject]]?)->Void)?, failure: FailureClosure?) {
let parameters: [String: AnyObject] = ["exclude_archived": excludeArchived]
client.api.request(endpoint, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(channels: response[type.rawValue+"s"] as? [Any])
success?(channels: response[type.rawValue+"s"] as? [[String: AnyObject]])
}) {(error) -> Void in
failure?(error: error)
}
}
private func mark(endpoint: SlackAPIEndpoint, channel: String, timestamp: String, success: ((ts: String)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": channel, "ts": timestamp]
networkInterface.request(endpoint: endpoint, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["channel": channel, "ts": timestamp]
client.api.request(endpoint, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(ts: timestamp)
}) {(error) -> Void in
@@ -679,8 +690,8 @@ public class SlackWebAPI {
}
private func setInfo(endpoint: SlackAPIEndpoint, type: InfoType, channel: String, text: String, success: ((success: Bool)->Void)?, failure: FailureClosure?) {
let parameters: [String: Any] = ["channel": channel, type.rawValue: text]
networkInterface.request(endpoint: endpoint, token: token, parameters: parameters, successClosure: {
let parameters: [String: AnyObject] = ["channel": channel, type.rawValue: text]
client.api.request(endpoint, token: client.token, parameters: parameters, successClosure: {
(response) -> Void in
success?(success: true)
}) {(error) -> Void in
@@ -689,8 +700,8 @@ public class SlackWebAPI {
}
//MARK: - Filter Nil Parameters
private func filterNilParameters(parameters: [String: Any?]) -> [String: Any] {
var finalParameters = [String: Any]()
private func filterNilParameters(parameters: [String: AnyObject?]) -> [String: AnyObject] {
var finalParameters = [String: AnyObject]()
for key in parameters.keys {
if parameters[key] != nil {
finalParameters[key] = parameters[key]!
@@ -700,16 +711,17 @@ public class SlackWebAPI {
}
//MARK: - Encode Attachments
private func encodeAttachments(attachments: [Attachment?]?) -> String? {
private func encodeAttachments(attachments: [Attachment?]?) -> NSString? {
if let attachments = attachments {
var attachmentArray: [Any] = []
var attachmentArray: [[String: AnyObject]] = []
for attachment in attachments {
if let attachment = attachment {
attachmentArray.append(attachment.dictionary())
}
}
do {
let string = try Jay().dataFromJson(attachmentArray).string()
let data = try NSJSONSerialization.dataWithJSONObject(attachmentArray, options: NSJSONWritingOptions.PrettyPrinted)
let string = NSString(data: data, encoding: NSUTF8StringEncoding)
return string
} catch _ {
@@ -719,11 +731,11 @@ public class SlackWebAPI {
}
//MARK: - Enumerate Do Not Distrub Status
private func enumerateDNDStauses(statuses: [String: Any]?) -> [String: DoNotDisturbStatus] {
private func enumerateDNDStauses(statuses: [String: AnyObject]?) -> [String: DoNotDisturbStatus] {
var retVal = [String: DoNotDisturbStatus]()
if let keys = statuses?.keys {
for key in keys {
retVal[key] = DoNotDisturbStatus(status: statuses?[key] as? [String: Any])
retVal[key] = DoNotDisturbStatus(status: statuses?[key] as? [String: AnyObject])
}
}
return retVal
@@ -1,5 +1,5 @@
//
// SlackWebAPIErrorHandling.swift
// SlackWebAPIErrorDispatcher.swift
//
// Copyright © 2016 Peter Zignego. All rights reserved.
//
@@ -21,7 +21,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
public enum SlackError: ErrorProtocol {
import Foundation
public enum SlackError: ErrorType {
case AccountInactive
case AlreadyArchived
case AlreadyInChannel
@@ -109,6 +111,8 @@ public enum SlackError: ErrorProtocol {
case UserListNotSupplied
case UserNotFound
case UserNotVisible
// Client
case ClientNetworkError
}
internal struct ErrorDispatcher {
+5 -5
View File
@@ -29,20 +29,20 @@ public struct Team {
internal(set) public var emailDomain: String?
internal(set) public var messageEditWindowMinutes: Int?
internal(set) public var overStorageLimit: Bool?
internal(set) public var prefs: [String: Any]?
internal(set) public var prefs: [String: AnyObject]?
internal(set) public var plan: String?
internal(set) public var icon: TeamIcon?
internal init?(team: [String: Any]?) {
internal init?(team: [String: AnyObject]?) {
id = team?["id"] as! String
name = team?["name"] as? String
domain = team?["domain"] as? String
emailDomain = team?["email_domain"] as? String
messageEditWindowMinutes = team?["msg_edit_window_mins"] as? Int
overStorageLimit = team?["over_storage_limit"] as? Bool
prefs = team?["prefs"] as? [String: Any]
prefs = team?["prefs"] as? [String: AnyObject]
plan = team?["plan"] as? String
icon = TeamIcon(icon: team?["icon"] as? [String: Any])
icon = TeamIcon(icon: team?["icon"] as? [String: AnyObject])
}
}
@@ -56,7 +56,7 @@ public struct TeamIcon {
internal(set) public var imageOriginal: String?
internal(set) public var imageDefault: Bool?
internal init?(icon: [String: Any]?) {
internal init?(icon: [String: AnyObject]?) {
image34 = icon?["image_34"] as? String
image44 = icon?["image_44"] as? String
image68 = icon?["image_68"] as? String
+31 -32
View File
@@ -21,13 +21,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
// MARK: - Edited
public struct Edited {
public let user: String?
public let ts: String?
internal init?(edited:[String: Any]?) {
internal init?(edited:[String: AnyObject]?) {
user = edited?["user"] as? String
ts = edited?["ts"] as? String
}
@@ -35,17 +36,17 @@ public struct Edited {
// MARK: - History
public struct History {
internal(set) public var latest: Double?
internal(set) public var latest: NSDate?
internal(set) public var messages = [Message]()
public let hasMore: Bool?
internal init?(history: [String: Any]?) {
internal init?(history: [String: AnyObject]?) {
if let latestStr = history?["latest"] as? String, latestDouble = Double(latestStr) {
latest = latestDouble
latest = NSDate(timeIntervalSince1970: NSTimeInterval(latestDouble))
}
if let msgs = history?["messages"] as? [Any] {
if let msgs = history?["messages"] as? [[String: AnyObject]] {
for message in msgs {
if let message = Message(message: message as? [String: Any]) {
if let message = Message(message: message) {
messages.append(message)
}
}
@@ -59,7 +60,7 @@ public struct Reaction {
public let name: String?
internal(set) public var users = [String: String]()
internal init?(reaction:[String: Any]?) {
internal init?(reaction:[String: AnyObject]?) {
name = reaction?["name"] as? String
}
@@ -73,20 +74,18 @@ public struct Reaction {
self.users = users
}
static func reactionsFromArray(array: [Any]) -> [String: Reaction] {
static func reactionsFromArray(array: [[String: AnyObject]]) -> [String: Reaction] {
var reactions = [String: Reaction]()
var userDictionary = [String: String]()
for r in array {
if let reaction = r as? [String: Any] {
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)
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
}
@@ -109,7 +108,7 @@ public struct Comment {
internal(set) public var stars: Int?
internal(set) public var reactions = [String: Reaction]()
internal init?(comment:[String: Any]?) {
internal init?(comment:[String: AnyObject]?) {
id = comment?["id"] as? String
created = comment?["created"] as? Int
user = comment?["user"] as? String
@@ -140,23 +139,23 @@ public struct Item {
public let comment: Comment?
public let fileCommentID: String?
internal init?(item:[String: Any]?) {
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? [String: Any])
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: Any])?.id == nil) {
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: Any])
comment = Comment(comment: item?["comment"] as? [String: AnyObject])
}
if (File(file: item?["file"] as? [String: Any])?.id == nil) {
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: Any])
file = File(file: item?["file"] as? [String: AnyObject])
}
fileCommentID = item?["file_comment"] as? String
@@ -175,7 +174,7 @@ public struct Topic {
public let creator: String?
public let lastSet: Int?
internal init?(topic: [String: Any]?) {
internal init?(topic: [String: AnyObject]?) {
value = topic?["value"] as? String
creator = topic?["creator"] as? String
lastSet = topic?["last_set"] as? Int
@@ -190,7 +189,7 @@ public struct DoNotDisturbStatus {
internal(set) public var snoozeEnabled: Bool?
internal(set) public var snoozeEndtime: Int?
internal init?(status: [String: Any]?) {
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
@@ -204,10 +203,10 @@ public struct DoNotDisturbStatus {
public struct CustomProfile {
internal(set) public var fields = [String: CustomProfileField]()
internal init?(profile: [String: Any]?) {
if let eventFields = profile?["fields"] as? [Any] {
internal init?(profile: [String: AnyObject]?) {
if let eventFields = profile?["fields"] as? [AnyObject] {
for field in eventFields {
if let cpf = CustomProfileField(field: field as? [String: Any]), id = cpf.id {
if let cpf = CustomProfileField(field: field as? [String: AnyObject]), id = cpf.id {
fields[id] = cpf
} else {
if let cpf = CustomProfileField(id: field as? String), id = cpf.id {
@@ -218,10 +217,10 @@ public struct CustomProfile {
}
}
internal init?(customFields: [String: Any]?) {
internal init?(customFields: [String: AnyObject]?) {
if let customFields = customFields {
for key in customFields.keys {
if let cpf = CustomProfileField(field: customFields[key] as? [String: Any]) {
if let cpf = CustomProfileField(field: customFields[key] as? [String: AnyObject]) {
self.fields[key] = cpf
}
}
@@ -242,7 +241,7 @@ public struct CustomProfileField {
internal(set) public var possibleValues: [String]?
internal(set) public var type: String?
internal init?(field: [String: Any]?) {
internal init?(field: [String: AnyObject]?) {
id = field?["id"] as? String
alt = field?["alt"] as? String
value = field?["value"] as? String
+6 -6
View File
@@ -37,7 +37,7 @@ public struct User {
internal(set) public var image192: String?
internal(set) public var customProfile: CustomProfile?
internal init?(profile: [String: Any]?) {
internal init?(profile: [String: AnyObject]?) {
firstName = profile?["first_name"] as? String
lastName = profile?["last_name"] as? String
realName = profile?["real_name"] as? String
@@ -49,7 +49,7 @@ public struct User {
image48 = profile?["image_48"] as? String
image72 = profile?["image_72"] as? String
image192 = profile?["image_192"] as? String
customProfile = CustomProfile(customFields: profile?["fields"] as? [String: Any])
customProfile = CustomProfile(customFields: profile?["fields"] as? [String: AnyObject])
}
}
@@ -73,15 +73,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: [String: Any]?
internal(set) public var preferences: [String: AnyObject]?
// Client properties
internal(set) public var userGroups: [String: String]?
internal init?(user: [String: Any]?) {
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? [String: Any])
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
@@ -96,7 +96,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? [String: Any]
preferences = user?["prefs"] as? [String: AnyObject]
}
internal init?(id: String?) {
+3 -3
View File
@@ -39,11 +39,11 @@ public struct UserGroup {
public let createdBy: String?
internal(set) public var updatedBy: String?
internal(set) public var deletedBy: String?
internal(set) public var preferences: [String: Any]?
internal(set) public var preferences: [String: AnyObject]?
internal(set) public var users: [String]?
internal(set) public var userCount: Int?
internal init?(userGroup: [String: Any]?) {
internal init?(userGroup: [String: AnyObject]?) {
id = userGroup?["id"] as? String
teamID = userGroup?["team_id"] as? String
isUserGroup = userGroup?["is_usergroup"] as? Bool
@@ -58,7 +58,7 @@ public struct UserGroup {
createdBy = userGroup?["created_by"] as? String
updatedBy = userGroup?["updated_by"] as? String
deletedBy = userGroup?["deleted_by"] as? String
preferences = userGroup?["prefs"] as? [String: Any]
preferences = userGroup?["prefs"] as? [String: AnyObject]
users = userGroup?["users"] as? [String]
if let count = userGroup?["user_count"] as? String {
userCount = Int(count)
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Peter Zignego. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Peter Zignego. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.1</string>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>