Merge branch 'feature/friends_in_contacts' into develop

This commit is contained in:
nixzhu
2015-06-02 01:22:39 +08:00
14 changed files with 560 additions and 137 deletions
+1
View File
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'APAddressBook/Swift'
pod 'TTTAttributedLabel'
pod 'FXBlurView'
pod 'Kingfisher'
+5
View File
@@ -20,6 +20,9 @@ PODS:
- AFNetworking/UIKit (2.5.4):
- AFNetworking/NSURLConnection
- AFNetworking/NSURLSession
- APAddressBook/Core (0.1.8)
- APAddressBook/Swift (0.1.8):
- APAddressBook/Core
- Base64 (1.0.1)
- FXBlurView (1.6.3)
- Kingfisher (1.4.1)
@@ -38,6 +41,7 @@ PODS:
DEPENDENCIES:
- AFNetworking
- APAddressBook/Swift
- FXBlurView
- Kingfisher
- MZFayeClient (from `../CatchLib-iOS/MZFayeClient/`)
@@ -52,6 +56,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AFNetworking: 05edc0ac4c4c8cf57bcf4b84be5b0744b6d8e71e
APAddressBook: cfff7589c5f9ee6ddbe23636b7723c2dbfa60a47
Base64: 4924bf3ca6fa559a5161ef717291bd450eb7bd1a
FXBlurView: c6d23f3d35af2c6282296a2930f61c6e2c788d01
Kingfisher: 962a21cdc2a7b0fa63be3b2c45ea6f180feda535
+12
View File
@@ -52,6 +52,7 @@
15606C18E1487982869C0A42 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD88F6095DB46DFAD41AB5DB /* Pods.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
50165C451AC2860900C7AEBE /* ConversationLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50165C441AC2860900C7AEBE /* ConversationLayout.swift */; };
502048241B0F1BB3002EBFC7 /* SearchedUsersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502048231B0F1BB3002EBFC7 /* SearchedUsersViewController.swift */; };
502280F81B1C3F2800E984EE /* FriendsInContactsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502280F71B1C3F2800E984EE /* FriendsInContactsViewController.swift */; };
5023DE261AB6856300B3EE96 /* ConversationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5023DE251AB6856300B3EE96 /* ConversationsViewController.swift */; };
5023DE2A1AB685BA00B3EE96 /* ContactsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5023DE291AB685BA00B3EE96 /* ContactsViewController.swift */; };
5023DE2D1AB685ED00B3EE96 /* DiscoverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5023DE2C1AB685ED00B3EE96 /* DiscoverViewController.swift */; };
@@ -263,6 +264,7 @@
2268251A75FF6766DC31CCFB /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
50165C441AC2860900C7AEBE /* ConversationLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationLayout.swift; path = ViewControllers/Conversation/ConversationLayout.swift; sourceTree = "<group>"; };
502048231B0F1BB3002EBFC7 /* SearchedUsersViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SearchedUsersViewController.swift; path = ViewControllers/SearchedUsers/SearchedUsersViewController.swift; sourceTree = "<group>"; };
502280F71B1C3F2800E984EE /* FriendsInContactsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FriendsInContactsViewController.swift; path = ViewControllers/FriendsInContacts/FriendsInContactsViewController.swift; sourceTree = "<group>"; };
5023DE251AB6856300B3EE96 /* ConversationsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationsViewController.swift; path = ViewControllers/Conversations/ConversationsViewController.swift; sourceTree = "<group>"; };
5023DE291AB685BA00B3EE96 /* ContactsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContactsViewController.swift; path = ViewControllers/Contacts/ContactsViewController.swift; sourceTree = "<group>"; };
5023DE2C1AB685ED00B3EE96 /* DiscoverViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscoverViewController.swift; path = ViewControllers/Discover/DiscoverViewController.swift; sourceTree = "<group>"; };
@@ -644,6 +646,14 @@
name = SearchedUsers;
sourceTree = "<group>";
};
502280F91B1C3F2F00E984EE /* FriendsInContacts */ = {
isa = PBXGroup;
children = (
502280F71B1C3F2800E984EE /* FriendsInContactsViewController.swift */,
);
name = FriendsInContacts;
sourceTree = "<group>";
};
5023DE271AB6856600B3EE96 /* ViewControllers */ = {
isa = PBXGroup;
children = (
@@ -667,6 +677,7 @@
508F8FCD1B01C80500461B0B /* SocialWorks */,
5064F6511B0AE2ED0089FAD4 /* AddFriends */,
502048251B0F1BB8002EBFC7 /* SearchedUsers */,
502280F91B1C3F2F00E984EE /* FriendsInContacts */,
0A943A7C1B0F8EB10022DD67 /* Base */,
0AB8F79B1B15D1DF00F4AF09 /* Nav */,
);
@@ -1675,6 +1686,7 @@
502AE52E1AB83879005BD199 /* UnderLineTextField.swift in Sources */,
508F8FD71B01EDB400461B0B /* DribbbleShotCell.swift in Sources */,
0A7A7D561AF5E00600A7F5F5 /* YepHelper.swift in Sources */,
502280F81B1C3F2800E984EE /* FriendsInContactsViewController.swift in Sources */,
508D17401ACCD2740092D666 /* YepButton.swift in Sources */,
506BB7F51AE4E0A500C1A2A0 /* SkillAnnotationHeader.swift in Sources */,
5023DE301AB6861500B3EE96 /* ProfileViewController.swift in Sources */,
+57 -11
View File
@@ -21,7 +21,7 @@
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="ECY-qd-LcH" userLabel="Conversations Table View">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="separatorColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<color key="separatorColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
<inset key="separatorInset" minX="90" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="dataSource" destination="vXZ-lx-hvc" id="wth-zY-jOa"/>
@@ -77,14 +77,14 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Gu7-gn-2ia">
<rect key="frame" x="0.0" y="270" width="600" height="100"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Swipe Up to Cancel" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zew-F7-znc">
<rect key="frame" x="223" y="59" width="153" height="20.5"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Swipe Up to Cancel" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Zew-F7-znc">
<rect key="frame" x="235" y="62" width="130" height="18"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="15"/>
<color key="textColor" red="1" green="0.0" blue="0.23529411764705882" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="swipe_up" translatesAutoresizingMaskIntoConstraints="NO" id="4p2-ZI-7q3">
<rect key="frame" x="287" y="41" width="25" height="8"/>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="swipe_up" translatesAutoresizingMaskIntoConstraints="NO" id="4p2-ZI-7q3">
<rect key="frame" x="287" y="44" width="25" height="8"/>
<constraints>
<constraint firstAttribute="height" constant="8" id="OSV-g6-oH8"/>
<constraint firstAttribute="width" constant="25" id="l0G-ny-LlM"/>
@@ -93,7 +93,6 @@
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" constant="600" id="5x8-l8-Hlh"/>
<constraint firstAttribute="height" constant="100" id="BJQ-S4-SYw"/>
<constraint firstAttribute="bottom" secondItem="Zew-F7-znc" secondAttribute="bottom" constant="20" id="DEv-gm-aP4"/>
<constraint firstAttribute="centerX" secondItem="Zew-F7-znc" secondAttribute="centerX" id="IrJ-B5-rtp"/>
@@ -129,7 +128,7 @@
</userDefinedRuntimeAttributes>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Hg3-Ss-sqD" userLabel="Add Location Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="406.5" y="20" width="173" height="260"/>
<rect key="frame" x="407" y="20" width="173" height="260"/>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
@@ -332,7 +331,7 @@
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="3hF-wd-yhY" userLabel="Contacts Table View">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="separatorColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<color key="separatorColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
<inset key="separatorInset" minX="90" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="dataSource" destination="fFS-0m-aok" id="XAO-GY-Ww5"/>
@@ -463,7 +462,7 @@
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="SPh-AI-uaZ">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="separatorColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<color key="separatorColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
<inset key="separatorInset" minX="90" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="dataSource" destination="5NR-G1-qqW" id="b7q-jQ-0Na"/>
@@ -685,7 +684,7 @@
<!--Add Friends View Controller-->
<scene sceneID="f0W-Bv-ApN">
<objects>
<viewController id="4Ji-K6-SJn" customClass="AddFriendsViewController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<viewController hidesBottomBarWhenPushed="YES" id="4Ji-K6-SJn" customClass="AddFriendsViewController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="hrO-Fa-cs0"/>
<viewControllerLayoutGuide type="bottom" id="mMl-TQ-Jon"/>
@@ -716,12 +715,59 @@
<connections>
<outlet property="addFriendsTableView" destination="RWL-Ot-i1T" id="znz-Hj-dRa"/>
<segue destination="sds-Gw-1Sf" kind="show" identifier="showSearchedUsers" id="kJd-wT-uPb"/>
<segue destination="KtV-SQ-G84" kind="show" identifier="showFriendsInContacts" id="wZV-dv-vt3"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8KG-Vq-jhm" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="157" y="1835"/>
</scene>
<!--Friends In Contacts View Controller-->
<scene sceneID="mYx-3f-c9A">
<objects>
<viewController storyboardIdentifier="FriendsInContactsViewController" id="KtV-SQ-G84" customClass="FriendsInContactsViewController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="fhI-xM-Gql"/>
<viewControllerLayoutGuide type="bottom" id="vOK-zT-WYA"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="rqb-L0-RRO">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="vdN-uK-rFe">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="separatorColor" red="0.90196079015731812" green="0.90196079015731812" blue="0.90196079015731812" alpha="1" colorSpace="calibratedRGB"/>
<inset key="separatorInset" minX="90" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="dataSource" destination="KtV-SQ-G84" id="OVq-w5-ONj"/>
<outlet property="delegate" destination="KtV-SQ-G84" id="VCQ-Db-f3r"/>
</connections>
</tableView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Ne0-z8-YLq">
<rect key="frame" x="290" y="184" width="20" height="20"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="Ne0-z8-YLq" secondAttribute="centerX" id="9X7-7I-MAy"/>
<constraint firstAttribute="bottom" secondItem="vdN-uK-rFe" secondAttribute="bottom" id="K2v-hJ-HU9"/>
<constraint firstItem="Ne0-z8-YLq" firstAttribute="top" secondItem="fhI-xM-Gql" secondAttribute="bottom" constant="120" id="NjG-bW-jWL"/>
<constraint firstItem="vdN-uK-rFe" firstAttribute="top" secondItem="rqb-L0-RRO" secondAttribute="top" id="dOq-t0-giI"/>
<constraint firstAttribute="trailing" secondItem="vdN-uK-rFe" secondAttribute="trailing" id="nZB-Gj-f5W"/>
<constraint firstItem="vdN-uK-rFe" firstAttribute="leading" secondItem="rqb-L0-RRO" secondAttribute="leading" id="vMg-c4-RUe"/>
</constraints>
</view>
<connections>
<outlet property="activityIndicator" destination="Ne0-z8-YLq" id="8pl-RI-dYU"/>
<outlet property="friendsTableView" destination="vdN-uK-rFe" id="aVj-dZ-a7Q"/>
<segue destination="AyC-pt-NR2" kind="show" identifier="showProfile" id="btf-on-xQx"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4Rg-GM-ojT" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="27" y="2683"/>
</scene>
<!--Searched Users View Controller-->
<scene sceneID="aQD-3E-kys">
<objects>
@@ -1272,8 +1318,8 @@
<image name="top_shadow" width="375" height="80"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="l4P-ds-ihU"/>
<segue reference="0bS-uM-LPI"/>
<segue reference="6No-Lc-7X4"/>
<segue reference="btf-on-xQx"/>
</inferredMetricsTieBreakers>
</document>
+4
View File
@@ -104,4 +104,8 @@ class YepConfig {
}
}
struct ContactsCell {
static let separatorInset = UIEdgeInsets(top: 0, left: 90, bottom: 0, right: 0)
}
}
+4
View File
@@ -57,4 +57,8 @@ extension UIColor {
return UIColor(red: 142.0/255.0, green: 142.0/255.0, blue: 147.0/255.0, alpha: 1.0)
}
class func yepCellSeparatorColor() -> UIColor {
return UIColor.lightGrayColor().colorWithAlphaComponent(0.3)
}
}
+86 -32
View File
@@ -449,6 +449,51 @@ func searchUsersByMobile(mobile: String, #failureHandler: ((Reason, String?) ->
}
}
typealias UploadContact = [String: String]
func friendsInContacts(contacts: [UploadContact], #failureHandler: ((Reason, String?) -> Void)?, #completion: [DiscoveredUser] -> Void) {
if let
contactsData = NSJSONSerialization.dataWithJSONObject(contacts, options: .PrettyPrinted, error: nil),
contactsString = NSString(data: contactsData, encoding: NSUTF8StringEncoding) {
let requestParameters: JSONDictionary = [
"contacts": contactsString
]
let parse: JSONDictionary -> [DiscoveredUser]? = { data in
if let registeredContacts = data["registered_users"] as? [JSONDictionary] {
//println("registeredContacts: \(registeredContacts)")
var discoveredUsers = [DiscoveredUser]()
for registeredContact in registeredContacts {
if let discoverUser = parseDiscoveredUser(registeredContact) {
discoveredUsers.append(discoverUser)
}
}
return discoveredUsers
} else {
return nil
}
}
let resource = authJsonResource(path: "/api/v1/contacts/upload", method: .POST, requestParameters: requestParameters, parse: parse)
if let failureHandler = failureHandler {
apiRequest({_ in}, baseURL, resource, failureHandler, completion)
} else {
apiRequest({_ in}, baseURL, resource, defaultFailureHandler, completion)
}
} else {
completion([])
}
}
// MARK: Friendships
private func headFriendships(#completion: JSONDictionary -> Void) {
@@ -527,47 +572,56 @@ struct DiscoveredUser {
let socialAccountProviders: [SocialAccountProvider]
}
let parseDiscoveredUser: JSONDictionary -> DiscoveredUser? = { userInfo in
if let
id = userInfo["id"] as? String,
nickname = userInfo["nickname"] as? String,
avatarURLString = userInfo["avatar_url"] as? String,
createdAtString = userInfo["created_at"] as? String,
lastSignInAtString = userInfo["last_sign_in_at"] as? String,
longitude = userInfo["longitude"] as? Double,
latitude = userInfo["latitude"] as? Double,
distance = userInfo["distance"] as? Double,
masterSkillsData = userInfo["master_skills"] as? [JSONDictionary],
learningSkillsData = userInfo["learning_skills"] as? [JSONDictionary],
socialAccountProvidersInfo = userInfo["providers"] as? [String: Bool] {
let createdAt = NSDate.dateWithISO08601String(createdAtString)
let lastSignInAt = NSDate.dateWithISO08601String(lastSignInAtString)
let masterSkills = skillsFromSkillsData(masterSkillsData)
let learningSkills = skillsFromSkillsData(learningSkillsData)
var socialAccountProviders = Array<DiscoveredUser.SocialAccountProvider>()
for (name, enabled) in socialAccountProvidersInfo {
let provider = DiscoveredUser.SocialAccountProvider(name: name, enabled: enabled)
socialAccountProviders.append(provider)
}
let introduction = userInfo["introduction"] as? String
let discoverUser = DiscoveredUser(id: id, nickname: nickname, introduction: introduction, avatarURLString: avatarURLString, createdAt: createdAt, lastSignInAt: lastSignInAt, longitude: longitude, latitude: latitude, distance: distance, masterSkills: masterSkills, learningSkills: learningSkills, socialAccountProviders: socialAccountProviders)
return discoverUser
}
return nil
}
let parseDiscoveredUsers: JSONDictionary -> [DiscoveredUser]? = { data in
println("discoverUsers: \(data)")
//println("discoverUsers: \(data)")
if let usersData = data["users"] as? [JSONDictionary] {
var discoveredUsers = [DiscoveredUser]()
for userInfo in usersData {
if let
id = userInfo["id"] as? String,
nickname = userInfo["nickname"] as? String,
avatarURLString = userInfo["avatar_url"] as? String,
createdAtString = userInfo["created_at"] as? String,
lastSignInAtString = userInfo["last_sign_in_at"] as? String,
longitude = userInfo["longitude"] as? Double,
latitude = userInfo["latitude"] as? Double,
distance = userInfo["distance"] as? Double,
masterSkillsData = userInfo["master_skills"] as? [JSONDictionary],
learningSkillsData = userInfo["learning_skills"] as? [JSONDictionary],
socialAccountProvidersInfo = userInfo["providers"] as? [String: Bool] {
let createdAt = NSDate.dateWithISO08601String(createdAtString)
let lastSignInAt = NSDate.dateWithISO08601String(lastSignInAtString)
let masterSkills = skillsFromSkillsData(masterSkillsData)
let learningSkills = skillsFromSkillsData(learningSkillsData)
var socialAccountProviders = Array<DiscoveredUser.SocialAccountProvider>()
for (name, enabled) in socialAccountProvidersInfo {
let provider = DiscoveredUser.SocialAccountProvider(name: name, enabled: enabled)
socialAccountProviders.append(provider)
}
let introduction = userInfo["introduction"] as? String
let discoverUser = DiscoveredUser(id: id, nickname: nickname, introduction: introduction, avatarURLString: avatarURLString, createdAt: createdAt, lastSignInAt: lastSignInAt, longitude: longitude, latitude: latitude, distance: distance, masterSkills: masterSkills, learningSkills: learningSkills, socialAccountProviders: socialAccountProviders)
discoveredUsers.append(discoverUser)
if let discoverUser = parseDiscoveredUser(userInfo) {
discoveredUsers.append(discoverUser)
}
}
@@ -7,6 +7,7 @@
//
import UIKit
import AddressBook
class AddFriendsViewController: UIViewController {
@@ -121,6 +122,57 @@ extension AddFriendsViewController: UITableViewDataSource, UITableViewDelegate {
return UITableViewCell()
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if indexPath.section == Section.More.rawValue {
switch indexPath.row {
case More.Contacts.rawValue:
switch ABAddressBookGetAuthorizationStatus() {
case .NotDetermined:
YepAlert.confirmOrCancel(title: NSLocalizedString("Notice", comment: ""), message: NSLocalizedString("Yep need to read your Contacts to continue this operation.\nIs that OK?", comment: ""), confirmTitle: NSLocalizedString("OK", comment: ""), cancelTitle: NSLocalizedString("No now", comment: ""), inViewController: self, withConfirmAction: {
if let addressBook: ABAddressBook = ABAddressBookCreateWithOptions(nil, nil)?.takeRetainedValue() {
ABAddressBookRequestAccessWithCompletion(addressBook, { granted, error in
if granted {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("showFriendsInContacts", sender: nil)
}
}
})
}
}, cancelAction: {
})
case .Authorized:
performSegueWithIdentifier("showFriendsInContacts", sender: nil)
case .Denied:
YepAlert.confirmOrCancel(title: NSLocalizedString("Sorry", comment: ""), message: NSLocalizedString("Yep can not read your Contacts!\nBut you can change it in iOS' Settings.\n", comment: ""), confirmTitle: NSLocalizedString("Change it now", comment: ""), cancelTitle: NSLocalizedString("Dismiss", comment: ""), inViewController: self, withConfirmAction: {
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
}, cancelAction: {
})
case .Restricted:
YepAlert.alertSorry(message: NSLocalizedString("Yep can not read your Contacts!", comment: ""), inViewController: self)
}
case More.FaceToFace.rawValue:
break
default:
break
}
}
}
}
extension AddFriendsViewController: UITextFieldDelegate {
@@ -25,23 +25,37 @@ class ContactsViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "syncFriendships", name: FriendsInContactsViewController.Notification.NewFriends, object: nil)
contactsTableView.separatorColor = UIColor.yepCellSeparatorColor()
contactsTableView.separatorInset = YepConfig.ContactsCell.separatorInset
contactsTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
contactsTableView.rowHeight = 80
contactsTableView.tableFooterView = UIView()
YepUserDefaults.nickname.bindListener("ContactsViewController.Nickname") { _ in
self.reloadContactsTableView()
self.updateContactsTableView()
}
YepUserDefaults.avatarURLString.bindListener("ContactsViewController.Avatar") { _ in
self.reloadContactsTableView()
self.updateContactsTableView()
}
}
func reloadContactsTableView() {
// MARK: Actions
func updateContactsTableView() {
contactsTableView.reloadData()
}
// MARK: Actions
func syncFriendships() {
syncFriendshipsAndDoFurtherAction {
dispatch_async(dispatch_get_main_queue()) {
self.updateContactsTableView()
}
}
}
@IBAction func presentAddFriends(sender: UIBarButtonItem) {
performSegueWithIdentifier("presentAddFriends", sender: nil)
@@ -63,8 +63,12 @@ class ConversationsViewController: UIViewController {
view.backgroundColor = UIColor.whiteColor()
conversationsTableView.separatorColor = UIColor.yepCellSeparatorColor()
conversationsTableView.separatorInset = YepConfig.ContactsCell.separatorInset
conversationsTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
conversationsTableView.rowHeight = 80
conversationsTableView.tableFooterView = UIView()
unreadMessagesToken = realm.addNotificationBlock { notification, realm in
self.haveUnreadMessages = countOfUnreadMessagesInRealm(realm) > 0
@@ -52,7 +52,10 @@ class DiscoverViewController: BaseViewController {
super.viewDidLoad()
view.backgroundColor = UIColor.whiteColor()
discoverTableView.separatorColor = UIColor.yepCellSeparatorColor()
discoverTableView.separatorInset = YepConfig.ContactsCell.separatorInset
discoverTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
discoverTableView.rowHeight = 80
@@ -0,0 +1,169 @@
//
// FriendsInContactsViewController.swift
// Yep
//
// Created by NIX on 15/6/1.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
import APAddressBook
class FriendsInContactsViewController: BaseViewController {
struct Notification {
static let NewFriends = "NewFriendsInContactsNotification"
}
@IBOutlet weak var friendsTableView: UITableView!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
lazy var addressBook: APAddressBook = {
let addressBook = APAddressBook()
addressBook.fieldsMask = APContactField(rawValue: APContactField.CompositeName.rawValue | APContactField.Phones.rawValue)
return addressBook
}()
var discoveredUsers = [DiscoveredUser]() {
didSet {
if discoveredUsers.count > 0 {
updateDiscoverTableView()
NSNotificationCenter.defaultCenter().postNotificationName(Notification.NewFriends, object: nil)
} else {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: friendsTableView.bounds.width, height: 240))
label.textAlignment = .Center
label.text = NSLocalizedString("No more new friends.", comment: "")
label.textColor = UIColor.lightGrayColor()
friendsTableView.tableFooterView = label
}
}
}
let cellIdentifier = "ContactsCell"
override func viewDidLoad() {
super.viewDidLoad()
title = NSLocalizedString("Available Friends", comment: "")
friendsTableView.separatorColor = UIColor.yepCellSeparatorColor()
friendsTableView.separatorInset = YepConfig.ContactsCell.separatorInset
friendsTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
friendsTableView.rowHeight = 80
friendsTableView.tableFooterView = UIView()
addressBook.loadContacts{ (contacts: [AnyObject]!, error: NSError!) in
if let contacts = contacts as? [APContact] {
var uploadContacts = [UploadContact]()
for contact in contacts {
let name = contact.compositeName
if let phones = contact.phones as? [String] {
for phone in phones {
let uploadContact: UploadContact = ["name": name, "number": phone]
uploadContacts.append(uploadContact)
}
}
}
//println(uploadContacts)
self.activityIndicator.startAnimating()
friendsInContacts(uploadContacts, failureHandler: { (reason, errorMessage) in
defaultFailureHandler(reason, errorMessage)
dispatch_async(dispatch_get_main_queue()) {
self.activityIndicator.stopAnimating()
}
}, completion: { discoveredUsers in
dispatch_async(dispatch_get_main_queue()) {
self.discoveredUsers = discoveredUsers
self.activityIndicator.stopAnimating()
}
})
} else if (error != nil) {
YepAlert.alertSorry(message: error.localizedDescription, inViewController: self)
}
}
}
// MARK: Actions
func updateDiscoverTableView() {
friendsTableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: UITableViewRowAnimation.Automatic)
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showProfile" {
if let indexPath = sender as? NSIndexPath {
let discoveredUser = discoveredUsers[indexPath.row]
let vc = segue.destinationViewController as! ProfileViewController
if discoveredUser.id != YepUserDefaults.userID.value {
vc.profileUser = ProfileUser.DiscoveredUserType(discoveredUser)
}
vc.setBackButtonWithTitle()
vc.hidesBottomBarWhenPushed = true
}
}
}
}
// MARK: UITableViewDataSource, UITableViewDelegate
extension FriendsInContactsViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return discoveredUsers.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! ContactsCell
let discoveredUser = discoveredUsers[indexPath.row]
let radius = min(CGRectGetWidth(cell.avatarImageView.bounds), CGRectGetHeight(cell.avatarImageView.bounds)) * 0.5
let avatarURLString = discoveredUser.avatarURLString
AvatarCache.sharedInstance.roundAvatarWithAvatarURLString(avatarURLString, withRadius: radius) { roundImage in
dispatch_async(dispatch_get_main_queue()) {
cell.avatarImageView.image = roundImage
}
}
cell.joinedDateLabel.text = discoveredUser.introduction
let distance = discoveredUser.distance.format(".1")
cell.lastTimeSeenLabel.text = "\(distance) km | \(discoveredUser.lastSignInAt.timeAgo)"
cell.nameLabel.text = discoveredUser.nickname
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
performSegueWithIdentifier("showProfile", sender: indexPath)
}
}
@@ -11,11 +11,11 @@ import RealmSwift
let profileAvatarAspectRatio: CGFloat = 12.0 / 16.0
enum SocialAccount: Int, Printable {
case Dribbble = 0
case Github
case Instagram
case Behance
enum SocialAccount: String, Printable {
case Dribbble = "dribbble"
case Github = "github"
case Instagram = "instagram"
case Behance = "behance"
var description: String {
@@ -82,7 +82,7 @@ enum ProfileUser {
func enabledSocialAccount(socialAccount: SocialAccount) -> Bool {
var accountEnabled = false
let providerName = socialAccount.description.lowercaseString
let providerName = socialAccount.rawValue
switch self {
@@ -235,8 +235,6 @@ class ProfileViewController: UIViewController {
}
}
//typealias SocialWorkProviderInfo = [String: Bool]
//var socialWorkProviderInfo = SocialWorkProviderInfo()
var dribbbleWork: DribbbleWork?
var instagramWork: InstagramWork?
@@ -289,14 +287,15 @@ class ProfileViewController: UIViewController {
let indexPath = NSIndexPath(forItem: 0, inSection: ProfileSection.Header.rawValue)
if let coverCell = self.profileCollectionView.cellForItemAtIndexPath(indexPath) as? ProfileHeaderCell {
let beginModifyPercentage: CGFloat = 0.9
let modifablePercentage: CGFloat = 1.0 - 0.9
let modifyPercentage: CGFloat = (progress - beginModifyPercentage)/modifablePercentage
coverCell.locationLabel.alpha = progress > beginModifyPercentage ? 0 : modifyPercentage
coverCell.avatarBlurImageView.alpha = progress < beginModifyPercentage ? 0 : modifyPercentage
self.topShadowImageView.alpha = progress < beginModifyPercentage ? 1.0 : 1 - modifyPercentage
let beginChangePercentage: CGFloat = 1 - 64 / self.collectionViewWidth * profileAvatarAspectRatio
let normalizedProgressForChange: CGFloat = (progress - beginChangePercentage) / (1 - beginChangePercentage)
coverCell.avatarBlurImageView.alpha = progress < beginChangePercentage ? 0 : normalizedProgressForChange
self.topShadowImageView.alpha = progress < beginChangePercentage ? 1 : 1 - normalizedProgressForChange
coverCell.locationLabel.alpha = progress < 0.5 ? 1 : 1 - min(1, (progress - 0.5) * 2 * 2) // alpha -> 0
}
}
}
@@ -421,15 +420,14 @@ class ProfileViewController: UIViewController {
}
} else if segue.identifier == "presentOAuth" {
if let item = sender as? Int {
if let providerName = sender as? String {
let nvc = segue.destinationViewController as! UINavigationController
let vc = nvc.topViewController as! OAuthViewController
vc.socialAccount = SocialAccount(rawValue: item)
vc.socialAccount = SocialAccount(rawValue: providerName)
vc.afterOAuthAction = { socialAccount in
// provider enabled
let providerName = socialAccount.description.lowercaseString
// self.socialWorkProviderInfo[providerName] = true
let providerName = socialAccount.rawValue
let realm = Realm()
@@ -451,9 +449,9 @@ class ProfileViewController: UIViewController {
}
} else if segue.identifier == "showSocialWorkGithub" {
if let item = sender as? Int {
if let providerName = sender as? String {
let vc = segue.destinationViewController as! SocialWorkGithubViewController
vc.socialAccount = SocialAccount(rawValue: item)
vc.socialAccount = SocialAccount(rawValue: providerName)
vc.profileUser = profileUser
vc.githubWork = githubWork
@@ -463,9 +461,9 @@ class ProfileViewController: UIViewController {
}
} else if segue.identifier == "showSocialWorkDribbble" {
if let item = sender as? Int {
if let providerName = sender as? String {
let vc = segue.destinationViewController as! SocialWorkDribbbleViewController
vc.socialAccount = SocialAccount(rawValue: item)
vc.socialAccount = SocialAccount(rawValue: providerName)
vc.profileUser = profileUser
vc.dribbbleWork = dribbbleWork
@@ -475,9 +473,9 @@ class ProfileViewController: UIViewController {
}
} else if segue.identifier == "showSocialWorkInstagram" {
if let item = sender as? Int {
if let providerName = sender as? String {
let vc = segue.destinationViewController as! SocialWorkInstagramViewController
vc.socialAccount = SocialAccount(rawValue: item)
vc.socialAccount = SocialAccount(rawValue: providerName)
vc.profileUser = profileUser
vc.instagramWork = instagramWork
@@ -683,7 +681,25 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
return 1
case ProfileSection.SocialAccount.rawValue:
return 3
if let profileUser = profileUser {
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
return discoveredUser.socialAccountProviders.filter({ $0.enabled }).count
case .UserType(let user):
if user.friendState == UserFriendState.Me.rawValue {
return user.socialAccountProviders.count
} else {
return user.socialAccountProviders.filter("enabled = true").count
}
}
}
return 0
default:
return 0
@@ -754,58 +770,80 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
case ProfileSection.SocialAccount.rawValue:
if let socialAccount = SocialAccount(rawValue: indexPath.row) {
if let profileUser = profileUser {
if socialAccount == .Github {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(socialAccountGithubCellIdentifier, forIndexPath: indexPath) as! ProfileSocialAccountGithubCell
var providerName = ""
cell.configureWithProfileUser(profileUser, socialAccount: socialAccount, githubWork: githubWork, completion: { githubWork in
self.githubWork = githubWork
})
return cell
switch profileUser {
} else {
case .DiscoveredUserType(let discoveredUser):
let provider = discoveredUser.socialAccountProviders.filter({ $0.enabled })[indexPath.row]
providerName = provider.name
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(socialAccountImagesCellIdentifier, forIndexPath: indexPath) as! ProfileSocialAccountImagesCell
case .UserType(let user):
if user.friendState == UserFriendState.Me.rawValue {
let provider = user.socialAccountProviders[indexPath.row]
providerName = provider.name
var socialWork: SocialWork?
switch socialAccount {
case .Dribbble:
if let dribbbleWork = dribbbleWork {
socialWork = SocialWork.Dribbble(dribbbleWork)
}
case .Instagram:
if let instagramWork = instagramWork {
socialWork = SocialWork.Instagram(instagramWork)
}
default:
break
} else {
let provider = user.socialAccountProviders.filter("enabled = true")[indexPath.row]
providerName = provider.name
}
cell.configureWithProfileUser(profileUser, socialAccount: socialAccount, socialWork: socialWork, completion: { socialWork in
switch socialWork {
case .Dribbble(let dribbbleWork):
self.dribbbleWork = dribbbleWork
case .Instagram(let instagramWork):
self.instagramWork = instagramWork
}
})
return cell
}
} else {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(socialAccountCellIdentifier, forIndexPath: indexPath) as! ProfileSocialAccountCell
return cell
if let socialAccount = SocialAccount(rawValue: providerName) {
if socialAccount == .Github {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(socialAccountGithubCellIdentifier, forIndexPath: indexPath) as! ProfileSocialAccountGithubCell
cell.configureWithProfileUser(profileUser, socialAccount: socialAccount, githubWork: githubWork, completion: { githubWork in
self.githubWork = githubWork
})
return cell
} else {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(socialAccountImagesCellIdentifier, forIndexPath: indexPath) as! ProfileSocialAccountImagesCell
var socialWork: SocialWork?
switch socialAccount {
case .Dribbble:
if let dribbbleWork = dribbbleWork {
socialWork = SocialWork.Dribbble(dribbbleWork)
}
case .Instagram:
if let instagramWork = instagramWork {
socialWork = SocialWork.Instagram(instagramWork)
}
default:
break
}
cell.configureWithProfileUser(profileUser, socialAccount: socialAccount, socialWork: socialWork, completion: { socialWork in
switch socialWork {
case .Dribbble(let dribbbleWork):
self.dribbbleWork = dribbbleWork
case .Instagram(let instagramWork):
self.instagramWork = instagramWork
}
})
return cell
}
}
}
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(socialAccountCellIdentifier, forIndexPath: indexPath) as! ProfileSocialAccountCell
return cell
default:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(skillCellIdentifier, forIndexPath: indexPath) as! SkillCell
@@ -944,9 +982,7 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
enabled = discoveredUser.socialAccountProviders.filter({ socialAccountProvider in
socialAccountProvider.enabled
}).count > 0
enabled = discoveredUser.socialAccountProviders.filter({ $0.enabled }).count > 0
case .UserType(let user):
if user.friendState != UserFriendState.Me.rawValue {
@@ -958,16 +994,7 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
return enabled ? CGSize(width: collectionViewWidth, height: 1) : CGSizeZero
case ProfileSection.SocialAccount.rawValue:
var enabled = true
// SocialAccount
if !profileUserIsMe, let profileUser = profileUser {
if let socialAccount = SocialAccount(rawValue: indexPath.row) {
enabled = profileUser.enabledSocialAccount(socialAccount)
}
}
return enabled ? CGSize(width: collectionViewWidth, height: 40) : CGSizeZero
return CGSize(width: collectionViewWidth, height: 40)
default:
return CGSizeZero
@@ -997,16 +1024,36 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
} else if indexPath.section == ProfileSection.SocialAccount.rawValue {
if let socialAccount = SocialAccount(rawValue: indexPath.item) {
if let profileUser = profileUser {
if let profileUser = profileUser {
var providerName = ""
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
let provider = discoveredUser.socialAccountProviders.filter({ $0.enabled })[indexPath.row]
providerName = provider.name
case .UserType(let user):
if user.friendState == UserFriendState.Me.rawValue {
let provider = user.socialAccountProviders[indexPath.row]
providerName = provider.name
} else {
let provider = user.socialAccountProviders.filter("enabled = true")[indexPath.row]
providerName = provider.name
}
}
if let socialAccount = SocialAccount(rawValue: providerName) {
if profileUser.enabledSocialAccount(socialAccount) {
performSegueWithIdentifier("showSocialWork\(socialAccount)", sender: indexPath.item)
performSegueWithIdentifier("showSocialWork\(socialAccount)", sender: providerName)
} else {
if profileUserIsMe {
performSegueWithIdentifier("presentOAuth", sender: indexPath.item)
performSegueWithIdentifier("presentOAuth", sender: providerName)
}
}
}
@@ -1019,7 +1066,7 @@ extension ProfileViewController: UIScrollViewDelegate {
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y < -300 {
YepAlert.alert(title: "Hello", message: "How are you?", dismissTitle: "I'm fine.", inViewController: self, withDismissAction: nil)
YepAlert.alert(title: "Hello", message: "My name is NIX. How are you?", dismissTitle: "I'm fine.", inViewController: self, withDismissAction: nil)
}
}
}
@@ -89,15 +89,23 @@ class SkillHomeViewController: CustomNavigationBarViewController {
override func viewDidLoad() {
super.viewDidLoad()
masterTableView.separatorColor = UIColor.yepCellSeparatorColor()
masterTableView.separatorInset = YepConfig.ContactsCell.separatorInset
masterTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
masterTableView.rowHeight = 80
masterTableView.tableFooterView = UIView()
masterTableView.dataSource = self
masterTableView.delegate = self
masterTableView.tag = SkillHomeState.Master.hashValue
learningtTableView.separatorColor = UIColor.yepCellSeparatorColor()
learningtTableView.separatorInset = YepConfig.ContactsCell.separatorInset
learningtTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
learningtTableView.rowHeight = 80
learningtTableView.tableFooterView = UIView()
learningtTableView.dataSource = self
learningtTableView.delegate = self
learningtTableView.tag = SkillHomeState.Learning.hashValue