Merge remote-tracking branch 'origin/feature/add_friends' into develop

# Conflicts:
#	Yep/ViewControllers/SocialWorks/SocialWorkGithubViewController.swift
This commit is contained in:
kevinzhow
2015-05-30 01:21:14 +08:00
121 changed files with 3843 additions and 1293 deletions
-1
View File
@@ -1 +0,0 @@
Versions/Current/Crashlytics
BIN
View File
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
Versions/Current/Headers
+62
View File
@@ -0,0 +1,62 @@
//
// CLSLogging.h
// Crashlytics
//
// Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
//
#import <Fabric/FABAttributes.h>
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif
FAB_START_NONNULL
/**
*
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
*
* Example output:
* -[AppDelegate login:] line 134 $ login start
*
* If you would like to change this macro, create a new header file, unset our define and then define
* your own version. Make sure this new header file is imported after the Crashlytics header file.
*
* #undef CLS_LOG
* #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
*
**/
#ifdef __OBJC__
#ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
#endif
/**
*
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
* and will only be visible in your Crashlytics dashboard.
*
**/
#ifdef __OBJC__
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSLogv(NSString *format, va_list ap) NS_FORMAT_FUNCTION(1,0);
/**
*
* Add logging that will be sent with your crash data. This logging will show up in the system.log
* and your Crashlytics dashboard. It is not recommended for Release builds.
*
**/
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSNSLogv(NSString *format, va_list ap) NS_FORMAT_FUNCTION(1,0);
#endif
FAB_END_NONNULL
+103
View File
@@ -0,0 +1,103 @@
//
// CLSReport.h
// Crashlytics
//
// Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Fabric/FABAttributes.h>
FAB_START_NONNULL
/**
* The CLSCrashReport protocol is deprecated. See the CLSReport class and the CrashyticsDelegate changes for details.
**/
@protocol CLSCrashReport <NSObject>
@property (nonatomic, copy, readonly) NSString *identifier;
@property (nonatomic, copy, readonly) NSDictionary *customKeys;
@property (nonatomic, copy, readonly) NSString *bundleVersion;
@property (nonatomic, copy, readonly) NSString *bundleShortVersionString;
@property (nonatomic, copy, readonly) NSDate *crashedOnDate;
@property (nonatomic, copy, readonly) NSString *OSVersion;
@property (nonatomic, copy, readonly) NSString *OSBuildVersion;
@end
/**
* The CLSReport exposes an interface to the phsyical report that Crashlytics has created. You can
* use this class to get information about the event, and can also set some values after the
* event has occured.
**/
@interface CLSReport : NSObject <CLSCrashReport>
- (instancetype)init NS_UNAVAILABLE;
/**
* Returns the session identifier for the report.
**/
@property (nonatomic, copy, readonly) NSString *identifier;
/**
* Returns the custom key value data for the report.
**/
@property (nonatomic, copy, readonly) NSDictionary *customKeys;
/**
* Returns the CFBundleVersion of the application that generated the report.
**/
@property (nonatomic, copy, readonly) NSString *bundleVersion;
/**
* Returns the CFBundleShortVersionString of the application that generated the report.
**/
@property (nonatomic, copy, readonly) NSString *bundleShortVersionString;
/**
* Returns the date that the report was created.
**/
@property (nonatomic, copy, readonly) NSDate *dateCreated;
/**
* Returns the os version that the application crashed on.
**/
@property (nonatomic, copy, readonly) NSString *OSVersion;
/**
* Returns the os build version that the application crashed on.
**/
@property (nonatomic, copy, readonly) NSString *OSBuildVersion;
/**
* Returns YES if the report contains any crash information. If the report
* contains only NSErrors, this will return NO.
**/
@property (nonatomic, assign, readonly) BOOL isCrash;
/**
* You can use this method to set, after the event, additional custom keys. The rules
* and semantics for this method are the same as those documented in Crashlytics.h. Be aware
* that the maximum size and count of custom keys is still enforced, and you can overwrite keys
* and/or cause excess keys to be deleted by using this method.
**/
- (void)setObjectValue:(id FAB_NULLABLE)value forKey:(NSString *)key;
/**
* Record an application-specific user identifier. See Crashlytics.h for details.
**/
@property (nonatomic, copy) NSString * FAB_NULLABLE userIdentifier;
/**
* Record a user name. See Crashlytics.h for details.
**/
@property (nonatomic, copy) NSString * FAB_NULLABLE userName;
/**
* Record a user email. See Crashlytics.h for details.
**/
@property (nonatomic, copy) NSString * FAB_NULLABLE userEmail;
@end
FAB_END_NONNULL
+37
View File
@@ -0,0 +1,37 @@
//
// CLSStackFrame.h
// Crashlytics
//
// Copyright 2015 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Fabric/FABAttributes.h>
FAB_START_NONNULL
/**
*
* This class is used in conjunction with -[Crashlytics recordCustomExceptionName:reason:frameArray:] to
* record information about non-ObjC/C++ exceptions. All information included here will be displayed
* in the Crashlytics UI, and can influence crash grouping. Be particularly careful with the use of the
* address property. If set, Crashlytics will attempt symbolication and could overwrite other properities
* in the process.
*
**/
@interface CLSStackFrame : NSObject
+ (instancetype)stackFrame;
+ (instancetype)stackFrameWithAddress:(NSUInteger)address;
+ (instancetype)stackFrameWithSymbol:(NSString *)symbol;
@property (nonatomic, copy) NSString * FAB_NULLABLE symbol;
@property (nonatomic, copy) NSString * FAB_NULLABLE library;
@property (nonatomic, copy) NSString * FAB_NULLABLE fileName;
@property (nonatomic, assign) uint32_t lineNumber;
@property (nonatomic, assign) uint64_t offset;
@property (nonatomic, assign) uint64_t address;
@end
FAB_END_NONNULL
+246
View File
@@ -0,0 +1,246 @@
//
// Crashlytics.h
// Crashlytics
//
// Copyright (c) 2015 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Fabric/FABAttributes.h>
#import "CLSLogging.h"
#import "CLSReport.h"
#import "CLSStackFrame.h"
#define CLS_DEPRECATED(x) __attribute__ ((deprecated(x)))
FAB_START_NONNULL
@protocol CrashlyticsDelegate;
@interface Crashlytics : NSObject
@property (nonatomic, readonly, copy) NSString *apiKey;
@property (nonatomic, readonly, copy) NSString *version;
@property (nonatomic, assign) BOOL debugMode;
/**
*
* The delegate can be used to influence decisions on reporting and behavior, as well as reacting
* to previous crashes.
*
* Make certain that the delegate is setup before starting Crashlytics with startWithAPIKey:... or
* via +[Fabric with:...]. Failure to do will result in missing any delegate callbacks that occur
* synchronously during start.
*
**/
@property (nonatomic, assign) id <CrashlyticsDelegate> FAB_NULLABLE delegate;
/**
*
* The recommended way to install Crashlytics into your application is to place a call
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions:/-applicationDidFinishLaunching:
* method.
*
* Note: Starting with 3.0, the submission process has been significantly improved. The delay parameter
* is no longer required to throttle submissions on launch, performance will be great without it.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay CLS_DEPRECATED("Crashlytics no longer needs or uses the delay parameter. Please use +startWithAPIKey: instead.");
/**
*
* If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
* these convenience methods to activate the framework and set the delegate in one call.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(id<CrashlyticsDelegate> FAB_NULLABLE)delegate;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(id<CrashlyticsDelegate> FAB_NULLABLE)delegate afterDelay:(NSTimeInterval)delay CLS_DEPRECATED("Crashlytics no longer needs or uses the delay parameter. Please use +startWithAPIKey:delegate: instead.");
/**
*
* Access the singleton Crashlytics instance.
*
**/
+ (Crashlytics *)sharedInstance;
/**
*
* The easiest ways to cause a crash - great for testing!
*
**/
- (void)crash;
- (void)throwException;
/**
*
* Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within
* the Crashlytics UI - but please be mindful of your end-user's privacy.
*
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a
* third-party observer but can be indexed and queried by you.
*
* Optionally, you may also specify the end-user's name or username, as well as email address if you
* do not have a system that works well with obscured identifiers.
*
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy
* policy. Data privacy is of our utmost concern.
*
**/
- (void)setUserIdentifier:(NSString * FAB_NULLABLE)identifier;
- (void)setUserName:(NSString * FAB_NULLABLE)name;
- (void)setUserEmail:(NSString * FAB_NULLABLE)email;
+ (void)setUserIdentifier:(NSString * FAB_NULLABLE)identifier CLS_DEPRECATED("Please access this method via +sharedInstance");
+ (void)setUserName:(NSString * FAB_NULLABLE)name CLS_DEPRECATED("Please access this method via +sharedInstance");
+ (void)setUserEmail:(NSString * FAB_NULLABLE)email CLS_DEPRECATED("Please access this method via +sharedInstance");
/**
*
* Set a value for a key to be associated with your crash data. When setting an object value, the object
* is converted to a string. This is typically done by calling -[NSObject description].
*
**/
- (void)setObjectValue:(id FAB_NULLABLE)value forKey:(NSString *)key;
- (void)setIntValue:(int)value forKey:(NSString *)key;
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
- (void)setFloatValue:(float)value forKey:(NSString *)key;
+ (void)setObjectValue:(id FAB_NULLABLE)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
+ (void)setIntValue:(int)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
+ (void)setFloatValue:(float)value forKey:(NSString *)key CLS_DEPRECATED("Please access this method via +sharedInstance");
/**
*
* This method can be used to record a single exception structure in a report. This is particularly useful
* when your code interacts with non-native languages like Lua, C#, or Javascript. This call can be
# expensive and should only be used shortly before process termination. This API is not intended be to used
* to log NSException objects. All safely-reportable NSExceptions are automatically captured by
* Crashlytics.
*
* The frameArray argument should contain only CLSStackFrame instances.
*
**/
- (void)recordCustomExceptionName:(NSString *)name reason:(NSString * FAB_NULLABLE)reason frameArray:(NSArray *)frameArray;
/**
* In Beta. Sign up at http://answers.io/labs to get on the list!
*
* @brief Log an event to be sent to Answers.
* @param eventName The event name as it will be shown in the dashboard.
* @discussion Example usage:
* @code [CrashlyticsKit logEvent:@"Tweet Viewed"];
*
*/
- (void)logEvent:(NSString *)eventName;
/**
* In Beta. Sign up at http://answers.io/labs to get on the list!
*
* @brief Log an event to be sent to Answers, optionally providing a dictionary of attributes. Attribute keys
* must be <code>NSString</code> and and values must be <code>NSNumber</code> or <code>NSString</code>.
* @param eventName The event name as it will be shown in the dashboard.
* @param attributes An NSDictionary with keys of type <code>NSString</code>, and values of type <code>NSNumber</code>
* or <code>NSString</code>. There may be at most 20 attributes for a particular event.
* @discussion How we treat <code>NSNumber</code>:
* We will provide information about the distribution of values over time.
*
* How we treat <code>NSStrings</code>:
* NSStrings are used as categorical data, allowing comparison across different category values.
* Strings are limited to a maximum length of 100 characters, attributes over this length will be
* truncated.
*
* When tracking the Tweet views to better understand user engagement, sending the tweet's length
* and the type of media present in the tweet allows you to track how tweet length and the type of media influence
* engagement.
* Example usage:
* @code [CrashlyticsKit logEvent:@"Tweet Viewed" attributes:@{
* @"Media Type": @"Image",
* @"Length": @120
* }];
*/
- (void)logEvent:(NSString *)eventName attributes:(NSDictionary * FAB_NULLABLE) attributes;
+ (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to -logEvent:");
+ (void)logEvent:(NSString *)eventName attributes:(NSDictionary * FAB_NULLABLE) attributes CLS_DEPRECATED("Please refer to -logEvent:attributes:");
@end
/**
*
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
* action on events that occur in the Crashlytics crash reporting system. You can make
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
* or through the convenience +startWithAPIKey:delegate: method.
*
**/
@protocol CrashlyticsDelegate <NSObject>
@optional
/**
*
* Called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called some time after the crash reporting
* process has begun. If you have specified a delay in one of the
* startWithAPIKey:... calls, this will take at least that long to be invoked.
*
**/
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics CLS_DEPRECATED("Please refer to -crashlyticsDidDetectReportForLastExecution:");
/**
*
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
* called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. A CLSCrashReport is passed back that contains data about
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
*
**/
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash CLS_DEPRECATED("Please refer to -crashlyticsDidDetectReportForLastExecution:");
/**
*
* Called when a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called synchronously on Crashlytics
* initialization. Your delegate must invoke the completionHandler, but does not need to do so
* synchronously, or even on the main thread. Invoking completionHandler with NO will cause the
* detected report to be deleted and not submitted to Crashlytics. This is useful for
* implementing permission prompts, or other more-complex forms of logic around submitting crashes.
*
* Failure to invoke the completionHandler will prevent submissions from being reported. Watch out.
*
* Just implementing this delegate method will disable all forms of synchronous report submission. This can
* impact the reliability of reporting crashes very early in application launch.
*
**/
- (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL submit))completionHandler;
/**
*
* If your app is running on an OS that supports it (OS X 10.9+, iOS 7.0+), Crashlytics will submit
* most reports using out-of-process background networking operations. This results in a significant
* improvement in reliability of reporting, as well as power and performance wins for your users.
* If you don't want this functionality, you can disable by returning NO from this method.
*
* Note: background submission is not supported for extensions on iOS or OS X.
*
**/
- (BOOL)crashlyticsCanUseBackgroundSessions:(Crashlytics *)crashlytics;
@end
/**
* `CrashlyticsKit` can be used as a parameter to `[Fabric with:@[CrashlyticsKit]];` in Objective-C. In Swift, use Crashlytics.sharedInstance()
*/
#define CrashlyticsKit [Crashlytics sharedInstance]
FAB_END_NONNULL
+55
View File
@@ -0,0 +1,55 @@
<?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>BuildMachineOSBuild</key>
<string>13F34</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>Crashlytics</string>
<key>CFBundleIdentifier</key>
<string>com.twitter.crashlytics.ios</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Crashlytics</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.0.8</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>50</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>12B411</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>DTPlatformVersion</key>
<string>8.1</string>
<key>DTSDKBuild</key>
<string>12B411</string>
<key>DTSDKName</key>
<string>iphoneos8.1</string>
<key>DTXcode</key>
<string>0611</string>
<key>DTXcodeBuild</key>
<string>6A2008a</string>
<key>MinimumOSVersion</key>
<string>5.0</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Crashlytics, Inc. All rights reserved.</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
</dict>
</plist>
+8 -3
View File
@@ -1,6 +1,11 @@
framework module Crashlytics {
umbrella header "Crashlytics.h"
header "Crashlytics.h"
header "CLSLogging.h"
header "CLSReport.h"
header "CLSStackFrame.h"
export *
module * { export * }
export *
link "z"
link "c++"
}
-1
View File
@@ -1 +0,0 @@
Versions/Current/Resources
Binary file not shown.
-225
View File
@@ -1,225 +0,0 @@
//
// Crashlytics.h
// Crashlytics
//
// Copyright 2013 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
*
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
*
* Example output:
* -[AppDelegate login:] line 134 $ login start
*
* If you would like to change this macro, create a new header file, unset our define and then define
* your own version. Make sure this new header file is imported after the Crashlytics header file.
*
* #undef CLS_LOG
* #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
*
**/
#ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
/**
*
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
* and will only be visible in your Crashlytics dashboard.
*
**/
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
/**
*
* Add logging that will be sent with your crash data. This logging will show up in the system.log
* and your Crashlytics dashboard. It is not recommended for Release builds.
*
**/
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
@protocol CrashlyticsDelegate;
@interface Crashlytics : NSObject
@property (nonatomic, readonly, copy) NSString *apiKey;
@property (nonatomic, readonly, copy) NSString *version;
@property (nonatomic, assign) BOOL debugMode;
@property (nonatomic, assign) NSObject <CrashlyticsDelegate> *delegate;
/**
*
* The recommended way to install Crashlytics into your application is to place a call
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
*
* This delay defaults to 1 second in order to generally give the application time to
* fully finish launching.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay;
/**
*
* If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
* these convenience methods to activate the framework and set the delegate in one call.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate afterDelay:(NSTimeInterval)delay;
/**
*
* Access the singleton Crashlytics instance.
*
**/
+ (Crashlytics *)sharedInstance;
/**
*
* The easiest way to cause a crash - great for testing!
*
**/
- (void)crash;
/**
*
* Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within
* the Crashlytics UI - but please be mindful of your end-user's privacy.
*
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a
* third-party observer but can be indexed and queried by you.
*
* Optionally, you may also specify the end-user's name or username, as well as email address if you
* do not have a system that works well with obscured identifiers.
*
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy
* policy. Data privacy is of our utmost concern.
*
**/
- (void)setUserIdentifier:(NSString *)identifier;
- (void)setUserName:(NSString *)name;
- (void)setUserEmail:(NSString *)email;
+ (void)setUserIdentifier:(NSString *)identifier;
+ (void)setUserName:(NSString *)name;
+ (void)setUserEmail:(NSString *)email;
/**
*
* Set a value for a key to be associated with your crash data.
*
**/
- (void)setObjectValue:(id)value forKey:(NSString *)key;
- (void)setIntValue:(int)value forKey:(NSString *)key;
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
- (void)setFloatValue:(float)value forKey:(NSString *)key;
+ (void)setObjectValue:(id)value forKey:(NSString *)key;
+ (void)setIntValue:(int)value forKey:(NSString *)key;
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
+ (void)setFloatValue:(float)value forKey:(NSString *)key;
@end
/**
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
* to delegate methods. If you want these values or the entire object to stay in memory retain
* them or copy them.
**/
@protocol CLSCrashReport <NSObject>
@required
/**
* Returns the session identifier for the crash report.
**/
@property (nonatomic, readonly) NSString *identifier;
/**
* Returns the custom key value data for the crash report.
**/
@property (nonatomic, readonly) NSDictionary *customKeys;
/**
* Returns the CFBundleVersion of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleVersion;
/**
* Returns the CFBundleShortVersionString of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleShortVersionString;
/**
* Returns the date that the application crashed at.
**/
@property (nonatomic, readonly) NSDate *crashedOnDate;
/**
* Returns the os version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSVersion;
/**
* Returns the os build version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSBuildVersion;
@end
/**
*
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
* action on events that occur in the Crashlytics crash reporting system. You can make
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
* or through the convenience startWithAPIKey:delegate:... methods.
*
**/
@protocol CrashlyticsDelegate <NSObject>
@optional
/**
*
* Called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called some time after the crash reporting
* process has begun. If you have specified a delay in one of the
* startWithAPIKey:... calls, this will take at least that long to be invoked.
*
**/
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
/**
*
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
* called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. A CLSCrashReport is passed back that contains data about
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
*
**/
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
@end
/**
* `CrashlyticsKit` can be used as a parameter to `[Fabric with:@[CrashlyticsKit]];` in Objective-C. In Swift, simply use `Crashlytics()`
*/
#define CrashlyticsKit [Crashlytics sharedInstance]
-30
View File
@@ -1,30 +0,0 @@
<?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>English</string>
<key>CFBundleExecutable</key>
<string>Crashlytics</string>
<key>CFBundleIdentifier</key>
<string>com.crashlytics.ios</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Crashlytics</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.10</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>45</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>MinimumOSVersion</key>
<string>4.0</string>
</dict>
</plist>
-1
View File
@@ -1 +0,0 @@
A
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Vendored Executable
BIN
View File
Binary file not shown.
+23
View File
@@ -0,0 +1,23 @@
//
// FABAttributes.h
// Fabric
//
// Created by Priyanka Joshi on 3/3/15.
// Copyright (c) 2015 Twitter. All rights reserved.
//
#pragma once
#define FAB_UNAVAILABLE(x) __attribute__((unavailable(x)))
#if __has_feature(nullability)
#define FAB_NONNULL __nonnull
#define FAB_NULLABLE __nullable
#define FAB_START_NONNULL _Pragma("clang assume_nonnull begin")
#define FAB_END_NONNULL _Pragma("clang assume_nonnull end")
#else
#define FAB_NONNULL
#define FAB_NULLABLE
#define FAB_START_NONNULL
#define FAB_END_NONNULL
#endif
+75
View File
@@ -0,0 +1,75 @@
//
// Fabric.h
//
// Copyright (c) 2014 Twitter. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "FABAttributes.h"
FAB_START_NONNULL
/**
* Fabric Base. Coordinates configuration and starts all provided kits.
*/
@interface Fabric : NSObject
/**
* Initialize Fabric and all provided kits. Call this method within your App Delegate's
* `application:didFinishLaunchingWithOptions:` and provide the kits you wish to use.
*
* For example, in Objective-C:
*
* `[Fabric with:@[TwitterKit, CrashlyticsKit, MoPubKit]];`
*
* Swift:
*
* `Fabric.with([Twitter(), Crashlytics(), MoPub()])`
*
* Only the first call to this method is honored. Subsequent calls are no-ops.
*
* @param kits An array of kit instances. Kits may provide a macro such as CrashlyticsKit which can be passed in as array elements in objective-c.
*
* @return Returns the shared Fabric instance. In most cases this can be ignored.
*/
+ (instancetype)with:(NSArray *)kits;
/**
* Returns the Fabric singleton object.
*/
+ (instancetype)sharedSDK;
/**
* This BOOL enables or disables debug logging, such as kit version information. The default value is NO.
*/
@property (nonatomic, assign) BOOL debug;
/**
* Unavailable. Use `+sharedSDK` to retrieve the shared Fabric instance.
*/
- (id)init FAB_UNAVAILABLE("Use +sharedSDK to retrieve the shared Fabric instance.");
/**
* Returns Fabrics's instance of the specified kit.
*
* @param klass The class of the kit.
*
* @return The kit instance of class klass which was provided to with: or nil.
*/
- (id FAB_NULLABLE)kitForClass:(Class)klass;
/**
* Returns a dictionary containing the kit configuration info for the provided kit.
* The configuration information is parsed from the application's Info.plist. This
* method is primarily intended to be used by kits to retrieve their configuration.
*
* @param kitInstance An instance of the kit whose configuration should be returned.
*
* @return A dictionary containing kit specific configuration information or nil if none exists.
*/
- (NSDictionary * FAB_NULLABLE)configurationDictionaryForKit:(id)kitInstance;
@end
FAB_END_NONNULL
+55
View File
@@ -0,0 +1,55 @@
<?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>BuildMachineOSBuild</key>
<string>13F34</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>Fabric</string>
<key>CFBundleIdentifier</key>
<string>io.fabric.sdk.ios</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Fabric</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.2.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>16</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>12B411</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>DTPlatformVersion</key>
<string>8.1</string>
<key>DTSDKBuild</key>
<string>12B411</string>
<key>DTSDKName</key>
<string>iphoneos8.1</string>
<key>DTXcode</key>
<string>0611</string>
<key>DTXcodeBuild</key>
<string>6A2008a</string>
<key>MinimumOSVersion</key>
<string>5.0</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Twitter. All rights reserved.</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
</dict>
</plist>
+6
View File
@@ -0,0 +1,6 @@
framework module Fabric {
umbrella header "Fabric.h"
export *
module * { export * }
}
Vendored Executable
BIN
View File
Binary file not shown.
+1
View File
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'FXBlurView'
pod 'Kingfisher'
pod 'WebViewJavascriptBridge'
pod 'pop'
+11 -8
View File
@@ -21,21 +21,23 @@ PODS:
- AFNetworking/NSURLConnection
- AFNetworking/NSURLSession
- Base64 (1.0.1)
- FXBlurView (1.6.3)
- Kingfisher (1.4.1)
- MZFayeClient (1.0.0):
- Base64 (~> 1.0.1)
- SocketRocket (~> 0.3.1-beta2)
- pop (1.0.7)
- Realm (0.92.3):
- Realm/Headers (= 0.92.3)
- Realm/Headers (0.92.3)
- RealmSwift (0.92.3):
- Realm (= 0.92.3)
- Realm (0.92.4):
- Realm/Headers (= 0.92.4)
- Realm/Headers (0.92.4)
- RealmSwift (0.92.4):
- Realm (= 0.92.4)
- SocketRocket (0.3.1-beta2)
- WebViewJavascriptBridge (4.1.4)
DEPENDENCIES:
- AFNetworking
- FXBlurView
- Kingfisher
- MZFayeClient (from `../CatchLib-iOS/MZFayeClient/`)
- pop
@@ -49,12 +51,13 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AFNetworking: 05edc0ac4c4c8cf57bcf4b84be5b0744b6d8e71e
Base64: 4924bf3ca6fa559a5161ef717291bd450eb7bd1a
FXBlurView: c6d23f3d35af2c6282296a2930f61c6e2c788d01
Kingfisher: 962a21cdc2a7b0fa63be3b2c45ea6f180feda535
MZFayeClient: 19df756a4c86c8f414668e6edc54fccfee54adbb
pop: 628ffc631644601567ee8bfaaaea493ebd7d0923
Realm: bf604805d5e897850da488260f93889f510924b3
RealmSwift: a5e48c7d5774eaa299b0b3a843add3b55e7f0061
Realm: 4267bae2eb7cf4a1e06ef3dfa7fe96024b28074c
RealmSwift: af48a8dea1a60b6e890be94148bece9432487b56
SocketRocket: 7284ab9370a06c99aba92b2fe3a32aedd0f9a6fa
WebViewJavascriptBridge: f10ac16f2cd3adf2b941bd79477c55a8f6e01044
COCOAPODS: 0.37.1
COCOAPODS: 0.37.2
+142 -4
View File
@@ -27,8 +27,14 @@
0A90187F1B01152800AE4B7F /* ProfileSocialAccountCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0A90187D1B01152800AE4B7F /* ProfileSocialAccountCell.xib */; };
0A9018821B0120A500AE4B7F /* OAuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A9018811B0120A500AE4B7F /* OAuthViewController.swift */; };
0A9018871B01321F00AE4B7F /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 0A9018861B01321F00AE4B7F /* WebViewJavascriptBridge.js.txt */; };
0A943A7B1B0F8EAE0022DD67 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A943A7A1B0F8EAE0022DD67 /* BaseViewController.swift */; };
0A944C251AC8BB2F00037A06 /* YepStorageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A944C241AC8BB2F00037A06 /* YepStorageService.swift */; };
0A98288F1B18D2BD001725B7 /* ChatStateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A98288D1B18D2BD001725B7 /* ChatStateCell.swift */; };
0A9828901B18D2BD001725B7 /* ChatStateCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0A98288E1B18D2BD001725B7 /* ChatStateCell.xib */; };
0AAFCFF91AC8CA5B00EB0EF8 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AAFCFF81AC8CA5B00EB0EF8 /* MobileCoreServices.framework */; };
0AB8F79A1B15D1DC00F4AF09 /* YepNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AB8F7991B15D1DC00F4AF09 /* YepNavigationController.swift */; };
0AC25F031B1100F0009E6E13 /* YepScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC25F021B1100F0009E6E13 /* YepScrollView.swift */; };
0AC25F061B1105D5009E6E13 /* YepChildScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC25F051B1105D5009E6E13 /* YepChildScrollView.swift */; };
0AD7EA5E1AC3ED1200617758 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA5D1AC3ED1200617758 /* CFNetwork.framework */; };
0AD7EA601AC3ED1900617758 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA5F1AC3ED1900617758 /* CoreFoundation.framework */; };
0AD7EA621AC3ED2100617758 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA611AC3ED2100617758 /* CoreTelephony.framework */; };
@@ -40,9 +46,12 @@
0AD7EA6E1AC3ED4A00617758 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA6D1AC3ED4A00617758 /* libz.dylib */; };
0AD7EA741AC3EE9600617758 /* libPushSDK-1.8.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AD7EA731AC3EE9600617758 /* libPushSDK-1.8.3.a */; };
0AD7EA771AC3EEB000617758 /* PushConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0AD7EA761AC3EEB000617758 /* PushConfig.plist */; };
0AFE75AF1AC43DE0005AA33E /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AFE75AE1AC43DE0005AA33E /* Crashlytics.framework */; };
0AEB1CC21B0E69B500178C9C /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AEB1CC11B0E69B500178C9C /* Fabric.framework */; };
0AEB1CC41B0E6A4B00178C9C /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AEB1CC31B0E6A4B00178C9C /* Crashlytics.framework */; };
0AEB1CC61B0E742400178C9C /* Double+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEB1CC51B0E742400178C9C /* Double+Yep.swift */; };
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 */; };
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 */; };
@@ -95,6 +104,7 @@
5053AD561AF83B0F00B3CBFA /* ChatRightLocationCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5053AD541AF83B0F00B3CBFA /* ChatRightLocationCell.xib */; };
5053AD5A1AF83B4200B3CBFA /* ChatLeftLocationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5053AD581AF83B4200B3CBFA /* ChatLeftLocationCell.swift */; };
5053AD5B1AF83B4200B3CBFA /* ChatLeftLocationCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5053AD591AF83B4200B3CBFA /* ChatLeftLocationCell.xib */; };
505498621B12FB0E0037E3BD /* ConversationMessagePreviewNavigationControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505498611B12FB0E0037E3BD /* ConversationMessagePreviewNavigationControllerDelegate.swift */; };
50553F8F1ADB8BA200F80B59 /* ChatSectionDateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50553F8D1ADB8BA200F80B59 /* ChatSectionDateCell.swift */; };
50553F901ADB8BA200F80B59 /* ChatSectionDateCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50553F8E1ADB8BA200F80B59 /* ChatSectionDateCell.xib */; };
50553F931ADBA50600F80B59 /* NSDate+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50553F921ADBA50600F80B59 /* NSDate+Yep.swift */; };
@@ -105,6 +115,11 @@
505EC8181ADF8151001D27E0 /* SkillCategoryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 505EC8161ADF8151001D27E0 /* SkillCategoryCell.xib */; };
505EC81C1ADFBE1B001D27E0 /* SkillSelectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505EC81A1ADFBE1B001D27E0 /* SkillSelectionCell.swift */; };
505EC81D1ADFBE1B001D27E0 /* SkillSelectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 505EC81B1ADFBE1B001D27E0 /* SkillSelectionCell.xib */; };
5064F6501B0AE2E60089FAD4 /* AddFriendsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5064F64F1B0AE2E60089FAD4 /* AddFriendsViewController.swift */; };
5064F6541B0B0E160089FAD4 /* AddFriendSearchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5064F6521B0B0E160089FAD4 /* AddFriendSearchCell.swift */; };
5064F6551B0B0E160089FAD4 /* AddFriendSearchCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5064F6531B0B0E160089FAD4 /* AddFriendSearchCell.xib */; };
5064F6591B0B14420089FAD4 /* AddFriendMoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5064F6571B0B14420089FAD4 /* AddFriendMoreCell.swift */; };
5064F65A1B0B14420089FAD4 /* AddFriendMoreCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5064F6581B0B14420089FAD4 /* AddFriendMoreCell.xib */; };
506923121ADE025200D27574 /* Waver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506923111ADE025200D27574 /* Waver.swift */; };
506923141ADE025F00D27574 /* YepRefreshView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506923131ADE025F00D27574 /* YepRefreshView.swift */; };
506BB7F51AE4E0A500C1A2A0 /* SkillAnnotationHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506BB7F31AE4E0A500C1A2A0 /* SkillAnnotationHeader.swift */; };
@@ -173,6 +188,7 @@
50E114F91ABC137A00F13000 /* YepServiceSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E114F81ABC137A00F13000 /* YepServiceSync.swift */; };
50E114FC1ABC549300F13000 /* ContactsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E114FA1ABC549300F13000 /* ContactsCell.swift */; };
50E114FD1ABC549300F13000 /* ContactsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50E114FB1ABC549300F13000 /* ContactsCell.xib */; };
50E18BB71B180F7D0076C3C6 /* SayHiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E18BB61B180F7D0076C3C6 /* SayHiView.swift */; };
50E61CEB1AF1F69D00908A9D /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E61CEA1AF1F69D00908A9D /* ConversationTitleView.swift */; };
50EB8C5E1AE78AB9001AC1EE /* YepAsset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50EB8C5D1AE78AB9001AC1EE /* YepAsset.swift */; };
50EB8CBF1AE89ED8001AC1EE /* ChatLeftVideoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50EB8CBD1AE89ED8001AC1EE /* ChatLeftVideoCell.swift */; };
@@ -218,8 +234,14 @@
0A90187D1B01152800AE4B7F /* ProfileSocialAccountCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ProfileSocialAccountCell.xib; path = Views/Cells/ProfileSocialAccount/ProfileSocialAccountCell.xib; sourceTree = "<group>"; };
0A9018811B0120A500AE4B7F /* OAuthViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OAuthViewController.swift; path = ViewControllers/OAuth/OAuthViewController.swift; sourceTree = "<group>"; };
0A9018861B01321F00AE4B7F /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = "<group>"; };
0A943A7A1B0F8EAE0022DD67 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BaseViewController.swift; path = ViewControllers/Base/BaseViewController.swift; sourceTree = "<group>"; };
0A944C241AC8BB2F00037A06 /* YepStorageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepStorageService.swift; path = Services/YepStorageService.swift; sourceTree = "<group>"; };
0A98288D1B18D2BD001725B7 /* ChatStateCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatStateCell.swift; path = Views/Cells/ChatState/ChatStateCell.swift; sourceTree = "<group>"; };
0A98288E1B18D2BD001725B7 /* ChatStateCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ChatStateCell.xib; path = Views/Cells/ChatState/ChatStateCell.xib; sourceTree = "<group>"; };
0AAFCFF81AC8CA5B00EB0EF8 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
0AB8F7991B15D1DC00F4AF09 /* YepNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepNavigationController.swift; path = ViewControllers/Nav/YepNavigationController.swift; sourceTree = "<group>"; };
0AC25F021B1100F0009E6E13 /* YepScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepScrollView.swift; path = Views/ScrollView/YepScrollView.swift; sourceTree = "<group>"; };
0AC25F051B1105D5009E6E13 /* YepChildScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepChildScrollView.swift; path = Views/ScrollView/YepChildScrollView.swift; sourceTree = "<group>"; };
0AD7EA511AC3EA6F00617758 /* JPushSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JPushSDK.framework; path = "Pods/../build/Debug-iphoneos/Pods/JPushSDK.framework"; sourceTree = "<group>"; };
0AD7EA581AC3EAF300617758 /* Yep-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Yep-Bridging-Header.h"; sourceTree = "<group>"; };
0AD7EA5B1AC3ECD700617758 /* libPushSDK-1.8.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPushSDK-1.8.3.a"; path = "Yep/lib/libPushSDK-1.8.3.a"; sourceTree = "<group>"; };
@@ -235,9 +257,12 @@
0AD7EA721AC3EE9600617758 /* APService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = APService.h; path = JPush/APService.h; sourceTree = "<group>"; };
0AD7EA731AC3EE9600617758 /* libPushSDK-1.8.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPushSDK-1.8.3.a"; path = "JPush/libPushSDK-1.8.3.a"; sourceTree = "<group>"; };
0AD7EA761AC3EEB000617758 /* PushConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PushConfig.plist; path = JPush/PushConfig.plist; sourceTree = "<group>"; };
0AFE75AE1AC43DE0005AA33E /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = Yep/Crashlytics.framework; sourceTree = "<group>"; };
0AEB1CC11B0E69B500178C9C /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
0AEB1CC31B0E6A4B00178C9C /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = "<group>"; };
0AEB1CC51B0E742400178C9C /* Double+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Double+Yep.swift"; path = "Extensions/Double+Yep.swift"; sourceTree = "<group>"; };
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>"; };
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>"; };
@@ -290,6 +315,7 @@
5053AD541AF83B0F00B3CBFA /* ChatRightLocationCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ChatRightLocationCell.xib; path = Views/Cells/ChatRightLocation/ChatRightLocationCell.xib; sourceTree = "<group>"; };
5053AD581AF83B4200B3CBFA /* ChatLeftLocationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatLeftLocationCell.swift; path = Views/Cells/ChatLeftLocation/ChatLeftLocationCell.swift; sourceTree = "<group>"; };
5053AD591AF83B4200B3CBFA /* ChatLeftLocationCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ChatLeftLocationCell.xib; path = Views/Cells/ChatLeftLocation/ChatLeftLocationCell.xib; sourceTree = "<group>"; };
505498611B12FB0E0037E3BD /* ConversationMessagePreviewNavigationControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationMessagePreviewNavigationControllerDelegate.swift; path = ViewControllers/Conversation/ConversationMessagePreviewNavigationControllerDelegate.swift; sourceTree = "<group>"; };
50553F8D1ADB8BA200F80B59 /* ChatSectionDateCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatSectionDateCell.swift; path = Views/Cells/ChatSectionDate/ChatSectionDateCell.swift; sourceTree = "<group>"; };
50553F8E1ADB8BA200F80B59 /* ChatSectionDateCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ChatSectionDateCell.xib; path = Views/Cells/ChatSectionDate/ChatSectionDateCell.xib; sourceTree = "<group>"; };
50553F921ADBA50600F80B59 /* NSDate+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSDate+Yep.swift"; path = "Extensions/NSDate+Yep.swift"; sourceTree = "<group>"; };
@@ -300,6 +326,11 @@
505EC8161ADF8151001D27E0 /* SkillCategoryCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SkillCategoryCell.xib; path = Views/Cells/SkillCategory/SkillCategoryCell.xib; sourceTree = "<group>"; };
505EC81A1ADFBE1B001D27E0 /* SkillSelectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SkillSelectionCell.swift; path = Views/Cells/SkillSelection/SkillSelectionCell.swift; sourceTree = "<group>"; };
505EC81B1ADFBE1B001D27E0 /* SkillSelectionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SkillSelectionCell.xib; path = Views/Cells/SkillSelection/SkillSelectionCell.xib; sourceTree = "<group>"; };
5064F64F1B0AE2E60089FAD4 /* AddFriendsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFriendsViewController.swift; path = ViewControllers/AddFriends/AddFriendsViewController.swift; sourceTree = "<group>"; };
5064F6521B0B0E160089FAD4 /* AddFriendSearchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFriendSearchCell.swift; path = Views/Cells/AddFriendSearch/AddFriendSearchCell.swift; sourceTree = "<group>"; };
5064F6531B0B0E160089FAD4 /* AddFriendSearchCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AddFriendSearchCell.xib; path = Views/Cells/AddFriendSearch/AddFriendSearchCell.xib; sourceTree = "<group>"; };
5064F6571B0B14420089FAD4 /* AddFriendMoreCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFriendMoreCell.swift; path = Views/Cells/AddFriendMore/AddFriendMoreCell.swift; sourceTree = "<group>"; };
5064F6581B0B14420089FAD4 /* AddFriendMoreCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AddFriendMoreCell.xib; path = Views/Cells/AddFriendMore/AddFriendMoreCell.xib; sourceTree = "<group>"; };
506923111ADE025200D27574 /* Waver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Waver.swift; path = Views/AudioWaves/Waver.swift; sourceTree = "<group>"; };
506923131ADE025F00D27574 /* YepRefreshView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepRefreshView.swift; path = Views/PullToRefresh/YepRefreshView.swift; sourceTree = "<group>"; };
506BB7F31AE4E0A500C1A2A0 /* SkillAnnotationHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SkillAnnotationHeader.swift; path = Views/ReusableViews/SkillAnnotationHeader/SkillAnnotationHeader.swift; sourceTree = "<group>"; };
@@ -368,6 +399,7 @@
50E114F81ABC137A00F13000 /* YepServiceSync.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepServiceSync.swift; path = Services/YepServiceSync.swift; sourceTree = "<group>"; };
50E114FA1ABC549300F13000 /* ContactsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContactsCell.swift; path = Views/Cells/Contacts/ContactsCell.swift; sourceTree = "<group>"; };
50E114FB1ABC549300F13000 /* ContactsCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ContactsCell.xib; path = Views/Cells/Contacts/ContactsCell.xib; sourceTree = "<group>"; };
50E18BB61B180F7D0076C3C6 /* SayHiView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SayHiView.swift; path = Views/SayHi/SayHiView.swift; sourceTree = "<group>"; };
50E61CEA1AF1F69D00908A9D /* ConversationTitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationTitleView.swift; path = Views/ConversationTitle/ConversationTitleView.swift; sourceTree = "<group>"; };
50EB8C5D1AE78AB9001AC1EE /* YepAsset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepAsset.swift; path = Helpers/YepAsset.swift; sourceTree = "<group>"; };
50EB8CBD1AE89ED8001AC1EE /* ChatLeftVideoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatLeftVideoCell.swift; path = Views/Cells/ChatLeftVideo/ChatLeftVideoCell.swift; sourceTree = "<group>"; };
@@ -386,6 +418,7 @@
buildActionMask = 2147483647;
files = (
0AD7EA681AC3ED3600617758 /* Foundation.framework in Frameworks */,
0AEB1CC41B0E6A4B00178C9C /* Crashlytics.framework in Frameworks */,
0A02E46F1AC9208A00235DBF /* libxml2.dylib in Frameworks */,
0AAFCFF91AC8CA5B00EB0EF8 /* MobileCoreServices.framework in Frameworks */,
0AD7EA741AC3EE9600617758 /* libPushSDK-1.8.3.a in Frameworks */,
@@ -396,8 +429,8 @@
0AD7EA641AC3ED2A00617758 /* SystemConfiguration.framework in Frameworks */,
0AD7EA621AC3ED2100617758 /* CoreTelephony.framework in Frameworks */,
0AD7EA601AC3ED1900617758 /* CoreFoundation.framework in Frameworks */,
0AEB1CC21B0E69B500178C9C /* Fabric.framework in Frameworks */,
0AD7EA5E1AC3ED1200617758 /* CFNetwork.framework in Frameworks */,
0AFE75AF1AC43DE0005AA33E /* Crashlytics.framework in Frameworks */,
15606C18E1487982869C0A42 /* Pods.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -559,6 +592,40 @@
name = WebViewJSBridge;
sourceTree = "<group>";
};
0A943A7C1B0F8EB10022DD67 /* Base */ = {
isa = PBXGroup;
children = (
0A943A7A1B0F8EAE0022DD67 /* BaseViewController.swift */,
);
name = Base;
sourceTree = "<group>";
};
0A9828911B18D2C3001725B7 /* ChatState */ = {
isa = PBXGroup;
children = (
0A98288E1B18D2BD001725B7 /* ChatStateCell.xib */,
0A98288D1B18D2BD001725B7 /* ChatStateCell.swift */,
);
name = ChatState;
sourceTree = "<group>";
};
0AB8F79B1B15D1DF00F4AF09 /* Nav */ = {
isa = PBXGroup;
children = (
0AB8F7991B15D1DC00F4AF09 /* YepNavigationController.swift */,
);
name = Nav;
sourceTree = "<group>";
};
0AC25F041B1100F3009E6E13 /* ScrollView */ = {
isa = PBXGroup;
children = (
0AC25F021B1100F0009E6E13 /* YepScrollView.swift */,
0AC25F051B1105D5009E6E13 /* YepChildScrollView.swift */,
);
name = ScrollView;
sourceTree = "<group>";
};
0AD7EA751AC3EE9B00617758 /* JPush */ = {
isa = PBXGroup;
children = (
@@ -569,6 +636,14 @@
name = JPush;
sourceTree = "<group>";
};
502048251B0F1BB8002EBFC7 /* SearchedUsers */ = {
isa = PBXGroup;
children = (
502048231B0F1BB3002EBFC7 /* SearchedUsersViewController.swift */,
);
name = SearchedUsers;
sourceTree = "<group>";
};
5023DE271AB6856600B3EE96 /* ViewControllers */ = {
isa = PBXGroup;
children = (
@@ -590,6 +665,10 @@
507CF1691AFC84AA00E261B4 /* CustomNavigationBar */,
0A9018831B0120A800AE4B7F /* OAuth */,
508F8FCD1B01C80500461B0B /* SocialWorks */,
5064F6511B0AE2ED0089FAD4 /* AddFriends */,
502048251B0F1BB8002EBFC7 /* SearchedUsers */,
0A943A7C1B0F8EB10022DD67 /* Base */,
0AB8F79B1B15D1DF00F4AF09 /* Nav */,
);
name = ViewControllers;
sourceTree = "<group>";
@@ -640,6 +719,7 @@
50A9D44A1ACD37A8000B2599 /* NSFileManager+Yep.swift */,
50553F921ADBA50600F80B59 /* NSDate+Yep.swift */,
508F8FE11B04B1F900461B0B /* UIDevice+Yep.swift */,
0AEB1CC51B0E742400178C9C /* Double+Yep.swift */,
);
name = Extensions;
sourceTree = "<group>";
@@ -660,6 +740,8 @@
50E61CEC1AF1F6A600908A9D /* ConversationTitle */,
0A1CAC711AFA481900826B45 /* SkillHomeHeaderView */,
0A1CAC741AFA526400826B45 /* SkillHomeSectionButton */,
0AC25F041B1100F3009E6E13 /* ScrollView */,
50E18BB81B180F8E0076C3C6 /* SayHi */,
);
name = Views;
sourceTree = "<group>";
@@ -698,6 +780,9 @@
508F8FD21B01D04F00461B0B /* GithubRepo */,
508F8FD91B01EDBC00461B0B /* DribbbleShot */,
508F8FE01B049AD400461B0B /* InstagramMedia */,
5064F6561B0B0E1B0089FAD4 /* AddFriendSearch */,
5064F65B1B0B14470089FAD4 /* AddFriendMore */,
0A9828911B18D2C3001725B7 /* ChatState */,
);
name = Cells;
sourceTree = "<group>";
@@ -886,6 +971,7 @@
503CAB421AC00CB100DFE830 /* ConversationViewController.swift */,
50165C441AC2860900C7AEBE /* ConversationLayout.swift */,
5076FC591AF9DF6B00D7381A /* ConversationMessagePreviewTransitionManager.swift */,
505498611B12FB0E0037E3BD /* ConversationMessagePreviewNavigationControllerDelegate.swift */,
);
name = Conversation;
sourceTree = "<group>";
@@ -962,6 +1048,32 @@
name = SkillSelection;
sourceTree = "<group>";
};
5064F6511B0AE2ED0089FAD4 /* AddFriends */ = {
isa = PBXGroup;
children = (
5064F64F1B0AE2E60089FAD4 /* AddFriendsViewController.swift */,
);
name = AddFriends;
sourceTree = "<group>";
};
5064F6561B0B0E1B0089FAD4 /* AddFriendSearch */ = {
isa = PBXGroup;
children = (
5064F6521B0B0E160089FAD4 /* AddFriendSearchCell.swift */,
5064F6531B0B0E160089FAD4 /* AddFriendSearchCell.xib */,
);
name = AddFriendSearch;
sourceTree = "<group>";
};
5064F65B1B0B14470089FAD4 /* AddFriendMore */ = {
isa = PBXGroup;
children = (
5064F6571B0B14420089FAD4 /* AddFriendMoreCell.swift */,
5064F6581B0B14420089FAD4 /* AddFriendMoreCell.xib */,
);
name = AddFriendMore;
sourceTree = "<group>";
};
506BB7F71AE4E0AA00C1A2A0 /* SkillAnnotationHeader */ = {
isa = PBXGroup;
children = (
@@ -1200,6 +1312,14 @@
name = Contacts;
sourceTree = "<group>";
};
50E18BB81B180F8E0076C3C6 /* SayHi */ = {
isa = PBXGroup;
children = (
50E18BB61B180F7D0076C3C6 /* SayHiView.swift */,
);
name = SayHi;
sourceTree = "<group>";
};
50E61CEC1AF1F6A600908A9D /* ConversationTitle */ = {
isa = PBXGroup;
children = (
@@ -1255,7 +1375,8 @@
67B708B60AAD1DEA82A6A682 /* Frameworks */ = {
isa = PBXGroup;
children = (
0AFE75AE1AC43DE0005AA33E /* Crashlytics.framework */,
0AEB1CC31B0E6A4B00178C9C /* Crashlytics.framework */,
0AEB1CC11B0E69B500178C9C /* Fabric.framework */,
0A02E46E1AC9208A00235DBF /* libxml2.dylib */,
0AAFCFF81AC8CA5B00EB0EF8 /* MobileCoreServices.framework */,
0AD7EA6D1AC3ED4A00617758 /* libz.dylib */,
@@ -1375,10 +1496,12 @@
50553F901ADB8BA200F80B59 /* ChatSectionDateCell.xib in Resources */,
502AE5411AB88862005BD199 /* SkillRankCell.xib in Resources */,
508F8FD11B01D04400461B0B /* GithubRepoCell.xib in Resources */,
0A9828901B18D2BD001725B7 /* ChatStateCell.xib in Resources */,
508F8FD81B01EDB400461B0B /* DribbbleShotCell.xib in Resources */,
502AE5541AB93215005BD199 /* ProfileFooterCell.xib in Resources */,
50CDBE4A1ACBAD3200459CE0 /* ChatLeftImageCell.xib in Resources */,
0A90187F1B01152800AE4B7F /* ProfileSocialAccountCell.xib in Resources */,
5064F6551B0B0E160089FAD4 /* AddFriendSearchCell.xib in Resources */,
508F8FC91B0161EF00461B0B /* ProfileSeparationLineCell.xib in Resources */,
50894CF61AEA4A01000981AF /* SettingsUserCell.xib in Resources */,
508D17481ACCF4710092D666 /* ChatLeftAudioCell.xib in Resources */,
@@ -1407,6 +1530,7 @@
503315981AC1017E0008A209 /* ChatLeftTextCell.xib in Resources */,
50894D031AEA6433000981AF /* EditProfileLessInfoCell.xib in Resources */,
0AD7EA771AC3EEB000617758 /* PushConfig.plist in Resources */,
5064F65A1B0B14420089FAD4 /* AddFriendMoreCell.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1508,6 +1632,7 @@
503315971AC1017E0008A209 /* ChatLeftTextCell.swift in Sources */,
0A8F54B11AB67D11004AD60E /* AppDelegate.swift in Sources */,
508F8FC81B0161EF00461B0B /* ProfileSeparationLineCell.swift in Sources */,
0AEB1CC61B0E742400178C9C /* Double+Yep.swift in Sources */,
508D174C1ACCF49B0092D666 /* ChatRightAudioCell.swift in Sources */,
502AE53D1AB87C0D005BD199 /* YepUserDefaults.swift in Sources */,
50EB8CC41AE89F12001AC1EE /* ChatRightVideoCell.swift in Sources */,
@@ -1523,6 +1648,8 @@
50E114F41ABBF9CC00F13000 /* Models.swift in Sources */,
5053AD551AF83B0F00B3CBFA /* ChatRightLocationCell.swift in Sources */,
50A9D4571ACD393A000B2599 /* YepWaverView.swift in Sources */,
0AC25F061B1105D5009E6E13 /* YepChildScrollView.swift in Sources */,
0A943A7B1B0F8EAE0022DD67 /* BaseViewController.swift in Sources */,
50165C451AC2860900C7AEBE /* ConversationLayout.swift in Sources */,
50EB8C5E1AE78AB9001AC1EE /* YepAsset.swift in Sources */,
508C2AA41AD661B3002B8097 /* UserStateCell.swift in Sources */,
@@ -1534,11 +1661,13 @@
508F8FD41B01E3D100461B0B /* SocialWorkDribbbleViewController.swift in Sources */,
50EB8CBF1AE89ED8001AC1EE /* ChatLeftVideoCell.swift in Sources */,
502AE5331AB86020005BD199 /* RegisterVerifyMobileViewController.swift in Sources */,
5064F6541B0B0E160089FAD4 /* AddFriendSearchCell.swift in Sources */,
0A1CAC6E1AFA42D400826B45 /* SkillHomeViewController.swift in Sources */,
502AE5401AB88862005BD199 /* SkillRankCell.swift in Sources */,
50C090A01ADE391600CC6389 /* AddSkillsReusableView.swift in Sources */,
5023DE2D1AB685ED00B3EE96 /* DiscoverViewController.swift in Sources */,
0A1CAC701AFA481600826B45 /* SkillHomeHeaderView.swift in Sources */,
0AB8F79A1B15D1DC00F4AF09 /* YepNavigationController.swift in Sources */,
502AE53A1AB871C1005BD199 /* YepAlert.swift in Sources */,
5039594E1B05E6E000797A3E /* ProfileSocialAccountGithubCell.swift in Sources */,
5053AD4D1AF79EEA00B3CBFA /* UserPickedLocationPin.swift in Sources */,
@@ -1560,6 +1689,8 @@
502AE5271AB72D06005BD199 /* YepNetworking.swift in Sources */,
5076C56A1AC46B9F00B22952 /* FayeService.swift in Sources */,
505EC8131ADE607D001D27E0 /* SkillCategoryButton.swift in Sources */,
0AC25F031B1100F0009E6E13 /* YepScrollView.swift in Sources */,
5064F6591B0B14420089FAD4 /* AddFriendMoreCell.swift in Sources */,
5099B9C71AB99F7B002F940B /* RegisterPickAvatarViewController.swift in Sources */,
504F41251ACE2D1D00FBB19A /* SampleView.swift in Sources */,
502AE5291AB81076005BD199 /* YepService.swift in Sources */,
@@ -1581,6 +1712,7 @@
506BB7F91AE5069500C1A2A0 /* RegisterPickSkillsSelectSkillsTransitionManager.swift in Sources */,
502AE52B1AB819AF005BD199 /* YepConfig.swift in Sources */,
0A271FD71ACA055400822DFC /* YepAudioService.swift in Sources */,
5064F6501B0AE2E60089FAD4 /* AddFriendsViewController.swift in Sources */,
507CF1681AFC84A500E261B4 /* CustomNavigationBarViewController.swift in Sources */,
0A3E60601ACCA9C0003DC853 /* String+Yep.swift in Sources */,
504F41571AD4D35400FBB19A /* ProfileLayout.swift in Sources */,
@@ -1588,10 +1720,14 @@
50A9D44B1ACD37A8000B2599 /* NSFileManager+Yep.swift in Sources */,
502AE5531AB93215005BD199 /* ProfileFooterCell.swift in Sources */,
50EB8CCB1AEA1AC0001AC1EE /* MediaView.swift in Sources */,
0A98288F1B18D2BD001725B7 /* ChatStateCell.swift in Sources */,
506923121ADE025200D27574 /* Waver.swift in Sources */,
0A5D83991AC5D91E000045BF /* ContactsSearchTableViewController.swift in Sources */,
502048241B0F1BB3002EBFC7 /* SearchedUsersViewController.swift in Sources */,
505498621B12FB0E0037E3BD /* ConversationMessagePreviewNavigationControllerDelegate.swift in Sources */,
0A944C251AC8BB2F00037A06 /* YepStorageService.swift in Sources */,
505EC8171ADF8151001D27E0 /* SkillCategoryCell.swift in Sources */,
50E18BB71B180F7D0076C3C6 /* SayHiView.swift in Sources */,
0A90187E1B01152800AE4B7F /* ProfileSocialAccountCell.swift in Sources */,
50894CF51AEA4A01000981AF /* SettingsUserCell.swift in Sources */,
5053AD5A1AF83B4200B3CBFA /* ChatLeftLocationCell.swift in Sources */,
@@ -1742,6 +1878,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Yep",
"$(PROJECT_DIR)/build/Debug-iphoneos/Pods",
"$(PROJECT_DIR)",
);
GCC_OPTIMIZATION_LEVEL = 0;
INFOPLIST_FILE = Yep/Info.plist;
@@ -1768,6 +1905,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Yep",
"$(PROJECT_DIR)/build/Debug-iphoneos/Pods",
"$(PROJECT_DIR)",
);
INFOPLIST_FILE = Yep/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+22 -7
View File
@@ -23,7 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
setSchemaVersion(3, Realm.defaultPath, { migration, oldSchemaVersion in
setSchemaVersion(5, Realm.defaultPath, { migration, oldSchemaVersion in
// We havent migrated anything yet, so oldSchemaVersion == 0
if oldSchemaVersion < 1 {
// Nothing to do!
@@ -36,6 +36,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if oldSchemaVersion < 3 {
}
if oldSchemaVersion < 4 {
}
if oldSchemaVersion < 5 {
}
})
Crashlytics.startWithAPIKey("3030ba006e21bcf8eb4a2127b6a7931ea6667486")
@@ -176,11 +182,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
func sync() {
syncFriendshipsAndDoFurtherAction {
syncGroupsAndDoFurtherAction {
syncUnreadMessagesAndDoFurtherAction {
dispatch_async(dispatch_get_main_queue()) {
NSNotificationCenter.defaultCenter().postNotificationName(YepNewMessagesReceivedNotification, object: nil)
syncMyInfoAndDoFurtherAction {
syncFriendshipsAndDoFurtherAction {
syncGroupsAndDoFurtherAction {
syncUnreadMessagesAndDoFurtherAction {
dispatch_async(dispatch_get_main_queue()) {
NSNotificationCenter.defaultCenter().postNotificationName(YepNewMessagesReceivedNotification, object: nil)
}
}
}
}
@@ -224,9 +232,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
NSShadowAttributeName: shadow,
NSFontAttributeName: UIFont.navigationBarTitleFont()
]
let barButtonTextAttributes = [
NSForegroundColorAttributeName: UIColor.yepTintColor(),
NSFontAttributeName: UIFont.barButtonFont()
]
UINavigationBar.appearance().titleTextAttributes = textAttributes
UINavigationBar.appearance().barTintColor = UIColor.whiteColor()
UIBarButtonItem.appearance().setTitleTextAttributes(barButtonTextAttributes, forState: UIControlState.Normal)
//UINavigationBar.appearance().setBackgroundImage(UIImage(named:"white"), forBarMetrics: .Default)
//UINavigationBar.appearance().shadowImage = UIImage()
//UINavigationBar.appearance().translucent = false
@@ -237,6 +251,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
//UITabBar.appearance().backgroundImage = UIImage(named:"white")
//UITabBar.appearance().shadowImage = UIImage()
UITabBar.appearance().tintColor = UIColor.yepTintColor()
UITabBar.appearance().barTintColor = UIColor.whiteColor()
//UITabBar.appearance().translucent = false
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+169 -54
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Ha4-ol-D2e">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="Ha4-ol-D2e">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
</dependencies>
@@ -18,9 +18,11 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="ECY-qd-LcH" userLabel="Conversations Table View">
<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"/>
<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"/>
<outlet property="delegate" destination="vXZ-lx-hvc" id="UpT-02-4Dg"/>
@@ -72,8 +74,35 @@
<outlet property="delegate" destination="la3-6z-2aH" id="zOV-zM-2KH"/>
</connections>
</collectionView>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q0w-sM-iIR" customClass="MessageToolbar" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="250" width="600" height="50"/>
<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"/>
<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"/>
<constraints>
<constraint firstAttribute="height" constant="8" id="OSV-g6-oH8"/>
<constraint firstAttribute="width" constant="25" id="l0G-ny-LlM"/>
</constraints>
</imageView>
</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"/>
<constraint firstItem="4p2-ZI-7q3" firstAttribute="centerX" secondItem="Zew-F7-znc" secondAttribute="centerX" id="PF6-KL-Z8X"/>
<constraint firstItem="Zew-F7-znc" firstAttribute="top" secondItem="4p2-ZI-7q3" secondAttribute="bottom" constant="10" id="b9o-gU-cOq"/>
</constraints>
</view>
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Q0w-sM-iIR" customClass="MessageToolbar" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="390" width="600" height="50"/>
<items/>
</toolbar>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="g11-Ob-rEy" userLabel="More Message Types View">
@@ -89,8 +118,8 @@
<userDefinedRuntimeAttribute type="string" keyPath="title" value="Choose photo"/>
</userDefinedRuntimeAttributes>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HcA-7v-16m" userLabel="Take Photo Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="213" y="20" width="174" height="260"/>
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HcA-7v-16m" userLabel="Take Photo Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="212" y="20" width="174" height="260"/>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
@@ -100,7 +129,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="407" y="20" width="173" height="260"/>
<rect key="frame" x="406.5" y="20" width="173" height="260"/>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
@@ -135,11 +164,14 @@
<constraint firstItem="g11-Ob-rEy" firstAttribute="leading" secondItem="P6X-OT-hT5" secondAttribute="leading" id="B04-LV-qWQ"/>
<constraint firstItem="Q0w-sM-iIR" firstAttribute="leading" secondItem="P6X-OT-hT5" secondAttribute="leading" id="BYY-lE-CF8"/>
<constraint firstItem="o5R-dM-KPW" firstAttribute="leading" secondItem="P6X-OT-hT5" secondAttribute="leading" id="BjN-8c-WjM"/>
<constraint firstItem="Gu7-gn-2ia" firstAttribute="centerX" secondItem="Q0w-sM-iIR" secondAttribute="centerX" id="MgC-bT-6sX"/>
<constraint firstItem="Gu7-gn-2ia" firstAttribute="width" secondItem="Q0w-sM-iIR" secondAttribute="width" id="Qru-A0-ifW"/>
<constraint firstAttribute="bottom" secondItem="Q0w-sM-iIR" secondAttribute="bottom" constant="160" id="Sf8-1u-t01"/>
<constraint firstItem="g11-Ob-rEy" firstAttribute="top" secondItem="Q0w-sM-iIR" secondAttribute="bottom" id="UC0-RV-osX"/>
<constraint firstAttribute="trailing" secondItem="g11-Ob-rEy" secondAttribute="trailing" id="cB1-tg-2P7"/>
<constraint firstItem="o5R-dM-KPW" firstAttribute="top" secondItem="P6X-OT-hT5" secondAttribute="top" id="d3q-cT-PCM"/>
<constraint firstAttribute="trailing" secondItem="o5R-dM-KPW" secondAttribute="trailing" id="qY6-Ly-z3r"/>
<constraint firstItem="Q0w-sM-iIR" firstAttribute="top" secondItem="Gu7-gn-2ia" secondAttribute="bottom" constant="20" id="xIr-4d-X2Q"/>
</constraints>
</view>
<connections>
@@ -149,10 +181,12 @@
<outlet property="messageToolbar" destination="Q0w-sM-iIR" id="vmQ-s1-SlQ"/>
<outlet property="messageToolbarBottomConstraint" destination="Sf8-1u-t01" id="f02-ze-rKh"/>
<outlet property="moreMessageTypesViewHeightConstraint" destination="faf-Xw-b0H" id="wNA-e7-3wx"/>
<outlet property="swipeUpView" destination="Gu7-gn-2ia" id="C4f-tg-leq"/>
<outlet property="takePhotoButton" destination="HcA-7v-16m" id="yfB-gA-lxG"/>
<segue destination="f92-fs-zdh" kind="presentation" identifier="presentMessageMedia" id="esY-9F-IrH"/>
<segue destination="wNI-He-VjY" kind="presentation" identifier="presentPickLocation" id="8Uc-bg-xSe"/>
<segue destination="AyC-pt-NR2" kind="show" identifier="showProfile" id="PTw-QB-dRp"/>
<segue destination="f92-fs-zdh" kind="show" identifier="showMessageMedia" id="6No-Lc-7X4"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="chH-Zx-2Ge" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -242,11 +276,11 @@
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="k4j-Ub-3bn" customClass="MediaView" customModule="Yep" customModuleProvider="target">
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="k4j-Ub-3bn" customClass="MediaView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2Cb-zQ-dUZ" customClass="MediaControlView" customModule="Yep" customModuleProvider="target">
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Cb-zQ-dUZ" customClass="MediaControlView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="540" width="600" height="60"/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
@@ -295,9 +329,11 @@
<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="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="3hF-wd-yhY" userLabel="Contacts Table View">
<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"/>
<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"/>
<outlet property="delegate" destination="fFS-0m-aok" id="clT-kA-HUJ"/>
@@ -313,9 +349,10 @@
</constraints>
</view>
<navigationItem key="navigationItem" title="Contacts" id="tYK-ax-VkQ">
<barButtonItem key="rightBarButtonItem" systemItem="search" id="JGC-Ux-Jad">
<barButtonItem key="rightBarButtonItem" systemItem="add" id="JGC-Ux-Jad">
<connections>
<segue destination="zAF-u5-qp5" kind="show" id="QyR-O5-XIC"/>
<action selector="presentAddFriends:" destination="fFS-0m-aok" id="9IM-fv-aba"/>
<segue destination="4Ji-K6-SJn" kind="show" identifier="presentAddFriends" id="jEu-61-ccJ"/>
</connections>
</barButtonItem>
</navigationItem>
@@ -372,7 +409,7 @@
</connections>
</searchDisplayController>
</objects>
<point key="canvasLocation" x="141" y="2691"/>
<point key="canvasLocation" x="693" y="3915"/>
</scene>
<!--Search Users View Controller-->
<scene sceneID="CWo-xc-jUy">
@@ -409,7 +446,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="f0E-uq-Sae" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="141" y="1999"/>
<point key="canvasLocation" x="-1" y="3925"/>
</scene>
<!--Discover-->
<scene sceneID="n5u-x5-QaP">
@@ -423,10 +460,19 @@
<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="SPh-AI-uaZ">
<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"/>
<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"/>
<outlet property="delegate" destination="5NR-G1-qqW" id="O3c-06-Lba"/>
</connections>
</tableView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="zzD-ES-eHf">
<rect key="frame" x="290" y="184" width="20" height="20"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
@@ -434,13 +480,21 @@
<constraint firstAttribute="bottom" secondItem="SPh-AI-uaZ" secondAttribute="bottom" id="HCe-mG-akd"/>
<constraint firstAttribute="trailing" secondItem="SPh-AI-uaZ" secondAttribute="trailing" id="HhT-qf-arz"/>
<constraint firstItem="SPh-AI-uaZ" firstAttribute="leading" secondItem="F0W-Z6-RS5" secondAttribute="leading" id="KqC-Vk-Ved"/>
<constraint firstAttribute="centerX" secondItem="zzD-ES-eHf" secondAttribute="centerX" id="NcD-eS-2bl"/>
<constraint firstItem="zzD-ES-eHf" firstAttribute="top" secondItem="y3q-lk-c8x" secondAttribute="bottom" constant="120" id="q7Q-WP-er9"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Discover" id="di2-g9-owW">
<barButtonItem key="rightBarButtonItem" title="NearBy" id="mve-O6-ube"/>
<barButtonItem key="rightBarButtonItem" title="Default" id="mve-O6-ube">
<connections>
<action selector="showFilters:" destination="5NR-G1-qqW" id="IQs-8r-M7C"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="activityIndicator" destination="zzD-ES-eHf" id="ysT-DA-Krf"/>
<outlet property="discoverTableView" destination="SPh-AI-uaZ" id="mB3-87-mQq"/>
<outlet property="filterButtonItem" destination="mve-O6-ube" id="379-Fa-dSw"/>
<segue destination="AyC-pt-NR2" kind="show" identifier="showProfile" id="l4P-ds-ihU"/>
</connections>
</viewController>
@@ -475,38 +529,19 @@
<outlet property="delegate" destination="AyC-pt-NR2" id="j2k-7a-66r"/>
</connections>
</collectionView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sfC-fv-gcr" userLabel="Say Hi View" customClass="SayHiView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="550" width="600" height="50"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="be0-Cf-Dol"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="top_shadow" translatesAutoresizingMaskIntoConstraints="NO" id="fut-Ug-l4V" userLabel="Shadow Image View">
<rect key="frame" x="0.0" y="0.0" width="600" height="80"/>
<constraints>
<constraint firstAttribute="height" constant="80" id="l36-59-jyr"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sfC-fv-gcr" userLabel="Say Hi View">
<rect key="frame" x="0.0" y="550" width="600" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="g8r-Vj-XaN" userLabel="Say Hi Button">
<rect key="frame" x="208" y="11" width="185" height="29"/>
<color key="backgroundColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="185" id="yZw-NR-HxS"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<state key="normal" title="Say Hi">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="sayHi:" destination="AyC-pt-NR2" eventType="touchUpInside" id="KdW-TT-FRw"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="centerY" secondItem="g8r-Vj-XaN" secondAttribute="centerY" id="CoJ-3z-kgW"/>
<constraint firstAttribute="height" constant="50" id="be0-Cf-Dol"/>
<constraint firstAttribute="centerX" secondItem="g8r-Vj-XaN" secondAttribute="centerX" id="dZg-1E-kjy"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
@@ -525,14 +560,14 @@
<navigationItem key="navigationItem" title="Profile" id="4pO-kT-amp">
<barButtonItem key="rightBarButtonItem" image="icon_settings" id="rTe-SV-2BV">
<connections>
<segue destination="XUP-IX-8LL" kind="show" id="srR-Ek-JSf"/>
<segue destination="XUP-IX-8LL" kind="show" identifier="showSettings" id="srR-Ek-JSf"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="profileCollectionView" destination="VZO-hp-fyU" id="xat-9E-RVG"/>
<outlet property="sayHiButton" destination="g8r-Vj-XaN" id="Evy-hG-CXL"/>
<outlet property="sayHiView" destination="sfC-fv-gcr" id="5bd-hx-FGY"/>
<outlet property="topShadowImageView" destination="fut-Ug-l4V" id="tWb-Tz-48h"/>
<segue destination="la3-6z-2aH" kind="show" identifier="showConversation" id="o3b-2D-AMq"/>
<segue destination="3gg-0l-MYn" kind="show" identifier="showSkillHome" id="Jw0-fk-BDi"/>
<segue destination="0NC-ph-TBU" kind="presentation" identifier="presentOAuth" id="nnt-hh-VMn"/>
@@ -602,7 +637,7 @@
<constraint firstAttribute="height" constant="160" id="zQ8-r2-xvU"/>
</constraints>
</view>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Qu8-bN-78f">
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Qu8-bN-78f" customClass="YepScrollView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="160" width="600" height="440"/>
</scrollView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="top_shadow" translatesAutoresizingMaskIntoConstraints="NO" id="nqy-s8-NRi" userLabel="Shadow Image View">
@@ -645,7 +680,85 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="O7a-Xh-Uff" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1204" y="1999"/>
<point key="canvasLocation" x="1002" y="1981"/>
</scene>
<!--Add Friends View Controller-->
<scene sceneID="f0W-Bv-ApN">
<objects>
<viewController 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"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Dtr-6Z-xvc">
<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="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" translatesAutoresizingMaskIntoConstraints="NO" id="RWL-Ot-i1T">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
<sections/>
<connections>
<outlet property="dataSource" destination="4Ji-K6-SJn" id="kdl-Q6-Ot3"/>
<outlet property="delegate" destination="4Ji-K6-SJn" id="wRO-6V-kYS"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="RWL-Ot-i1T" firstAttribute="leading" secondItem="Dtr-6Z-xvc" secondAttribute="leading" id="0eK-UP-PJP"/>
<constraint firstAttribute="trailing" secondItem="RWL-Ot-i1T" secondAttribute="trailing" id="W9g-oW-JQX"/>
<constraint firstAttribute="bottom" secondItem="RWL-Ot-i1T" secondAttribute="bottom" id="ffK-oF-sgC"/>
<constraint firstItem="RWL-Ot-i1T" firstAttribute="top" secondItem="Dtr-6Z-xvc" secondAttribute="top" id="xMx-Gt-bzW"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="7hc-4a-qfO"/>
<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"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8KG-Vq-jhm" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="157" y="1835"/>
</scene>
<!--Searched Users View Controller-->
<scene sceneID="aQD-3E-kys">
<objects>
<viewController storyboardIdentifier="SearchedUsersViewController" id="sds-Gw-1Sf" customClass="SearchedUsersViewController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="D8l-cJ-Rf1"/>
<viewControllerLayoutGuide type="bottom" id="lXP-Xa-dxg"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="wId-X1-Mzc">
<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="g8U-pG-JhU">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<connections>
<outlet property="dataSource" destination="sds-Gw-1Sf" id="TjN-Oa-tEx"/>
<outlet property="delegate" destination="sds-Gw-1Sf" id="XFJ-wF-OcC"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="g8U-pG-JhU" secondAttribute="trailing" id="EqT-Kf-FYL"/>
<constraint firstItem="g8U-pG-JhU" firstAttribute="leading" secondItem="wId-X1-Mzc" secondAttribute="leading" id="NnD-aG-NJB"/>
<constraint firstAttribute="bottom" secondItem="g8U-pG-JhU" secondAttribute="bottom" id="dKs-JH-0Gp"/>
<constraint firstItem="g8U-pG-JhU" firstAttribute="top" secondItem="wId-X1-Mzc" secondAttribute="top" id="otn-jU-lTE"/>
</constraints>
</view>
<connections>
<outlet property="searchedUsersTableView" destination="g8U-pG-JhU" id="JkD-Sn-KGi"/>
<segue destination="AyC-pt-NR2" kind="show" identifier="showProfile" id="hTj-2y-9h4"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="IY7-lg-OWx" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="939" y="2835"/>
</scene>
<!--Auth View Controller-->
<scene sceneID="4gu-P3-U3G">
@@ -692,7 +805,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="aYj-Hp-etu" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2041" y="2783"/>
<point key="canvasLocation" x="2041" y="2761"/>
</scene>
<!--Edit Profile View Controller-->
<scene sceneID="l0f-Y7-OKE">
@@ -817,7 +930,7 @@
<!--Chats-->
<scene sceneID="ySr-fW-tdP">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="hOb-vY-dSl" sceneMemberID="viewController">
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="hOb-vY-dSl" customClass="YepNavigationController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Chats" image="icon_chat" id="v0w-Lf-9uQ">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="image" keyPath="selectedImage" value="icon_chat_active"/>
@@ -840,7 +953,7 @@
<!--Contacts-->
<scene sceneID="CIQ-7C-4Qf">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="HI7-HE-lfi" sceneMemberID="viewController">
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="HI7-HE-lfi" customClass="YepNavigationController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Contacts" image="icon_contact" id="KN1-ry-ZuC">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="image" keyPath="selectedImage" value="icon_contact_active"/>
@@ -863,7 +976,7 @@
<!--Discover-->
<scene sceneID="I0q-3N-v5s">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="HFE-uY-fys" sceneMemberID="viewController">
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="HFE-uY-fys" customClass="YepNavigationController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Discover" image="icon_explore" id="NTl-bD-Fa2">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="image" keyPath="selectedImage" value="icon_explore_active"/>
@@ -886,7 +999,7 @@
<!--Profile-->
<scene sceneID="E1Z-RL-QZO">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="dwP-GL-7hj" sceneMemberID="viewController">
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="dwP-GL-7hj" customClass="YepNavigationController" customModule="Yep" customModuleProvider="target" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Profile" image="icon_me" id="zZf-BL-xLF">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="image" keyPath="selectedImage" value="icon_me_active"/>
@@ -1155,10 +1268,12 @@
<image name="icon_profile_phone" width="16" height="24"/>
<image name="icon_settings" width="30" height="30"/>
<image name="profile_avatar_frame" width="112" height="112"/>
<image name="swipe_up" width="21" height="6"/>
<image name="top_shadow" width="375" height="80"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="Snz-CT-4aa"/>
<segue reference="o3b-2D-AMq"/>
<segue reference="l4P-ds-ihU"/>
<segue reference="0bS-uM-LPI"/>
<segue reference="6No-Lc-7X4"/>
</inferredMetricsTieBreakers>
</document>
+9 -5
View File
@@ -217,6 +217,10 @@ class AvatarCache {
if let url = NSURL(string: user.avatarURLString) {
let roundImageKey = "round-\(radius)-\(url.hashValue)"
// 线Realm 线访
let avatarURLString = user.avatarURLString
let userID = user.userID
//
if let roundImage = cache.objectForKey(roundImageKey) as? UIImage {
completion(roundImage)
@@ -225,7 +229,7 @@ class AvatarCache {
//
if let avatar = user.avatar {
if avatar.avatarURLString == user.avatarURLString {
if avatar.avatarURLString == avatarURLString {
if let
avatarFileURL = NSFileManager.yepAvatarURLWithName(avatar.avatarFileName),
@@ -245,7 +249,7 @@ class AvatarCache {
let realm = Realm()
// 使 user.avatar, realm
if let avatar = avatarWithAvatarURLString(user.avatarURLString, inRealm: realm) {
if let avatar = avatarWithAvatarURLString(avatarURLString, inRealm: realm) {
realm.write {
realm.delete(avatar)
}
@@ -263,14 +267,14 @@ class AvatarCache {
dispatch_async(dispatch_get_main_queue()) {
let realm = Realm()
var avatar = avatarWithAvatarURLString(user.avatarURLString, inRealm: realm)
var avatar = avatarWithAvatarURLString(avatarURLString, inRealm: realm)
if avatar == nil {
let avatarFileName = NSUUID().UUIDString
if let avatarURL = NSFileManager.saveAvatarImage(image, withName: avatarFileName) {
let newAvatar = Avatar()
newAvatar.avatarURLString = user.avatarURLString
newAvatar.avatarURLString = avatarURLString
newAvatar.avatarFileName = avatarFileName
realm.write {
@@ -282,7 +286,7 @@ class AvatarCache {
}
// realm user线访 "Realm accessed from incorrect thread"
if let user = userWithUserID(user.userID, inRealm: realm) {
if let user = userWithUserID(userID, inRealm: realm) {
if user.avatar == nil, let avatar = avatar {
realm.write {
user.avatar = avatar
+1 -1
View File
@@ -82,7 +82,7 @@ class YepConfig {
struct Profile {
static let leftEdgeInset: CGFloat = UIDevice.matchMarginFrom(20, 38, 40)
static let rightEdgeInset: CGFloat = leftEdgeInset
static let introductionLabelFont = UIFont(name: "HelveticaNeue-Thin", size: 12)!
static let introductionLabelFont = UIFont(name: "Helvetica-Light", size: 14)!
}
struct Settings {
-1
View File
@@ -1 +0,0 @@
Versions/Current/Crashlytics
-1
View File
@@ -1 +0,0 @@
Versions/Current/Headers
-6
View File
@@ -1,6 +0,0 @@
framework module Crashlytics {
umbrella header "Crashlytics.h"
export *
module * { export * }
}
-1
View File
@@ -1 +0,0 @@
Versions/Current/Resources
Binary file not shown.
@@ -1,225 +0,0 @@
//
// Crashlytics.h
// Crashlytics
//
// Copyright 2013 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
*
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
*
* Example output:
* -[AppDelegate login:] line 134 $ login start
*
* If you would like to change this macro, create a new header file, unset our define and then define
* your own version. Make sure this new header file is imported after the Crashlytics header file.
*
* #undef CLS_LOG
* #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
*
**/
#ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
/**
*
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
* and will only be visible in your Crashlytics dashboard.
*
**/
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
/**
*
* Add logging that will be sent with your crash data. This logging will show up in the system.log
* and your Crashlytics dashboard. It is not recommended for Release builds.
*
**/
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
@protocol CrashlyticsDelegate;
@interface Crashlytics : NSObject
@property (nonatomic, readonly, copy) NSString *apiKey;
@property (nonatomic, readonly, copy) NSString *version;
@property (nonatomic, assign) BOOL debugMode;
@property (nonatomic, assign) NSObject <CrashlyticsDelegate> *delegate;
/**
*
* The recommended way to install Crashlytics into your application is to place a call
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
*
* This delay defaults to 1 second in order to generally give the application time to
* fully finish launching.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay;
/**
*
* If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
* these convenience methods to activate the framework and set the delegate in one call.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate afterDelay:(NSTimeInterval)delay;
/**
*
* Access the singleton Crashlytics instance.
*
**/
+ (Crashlytics *)sharedInstance;
/**
*
* The easiest way to cause a crash - great for testing!
*
**/
- (void)crash;
/**
*
* Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within
* the Crashlytics UI - but please be mindful of your end-user's privacy.
*
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a
* third-party observer but can be indexed and queried by you.
*
* Optionally, you may also specify the end-user's name or username, as well as email address if you
* do not have a system that works well with obscured identifiers.
*
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy
* policy. Data privacy is of our utmost concern.
*
**/
- (void)setUserIdentifier:(NSString *)identifier;
- (void)setUserName:(NSString *)name;
- (void)setUserEmail:(NSString *)email;
+ (void)setUserIdentifier:(NSString *)identifier;
+ (void)setUserName:(NSString *)name;
+ (void)setUserEmail:(NSString *)email;
/**
*
* Set a value for a key to be associated with your crash data.
*
**/
- (void)setObjectValue:(id)value forKey:(NSString *)key;
- (void)setIntValue:(int)value forKey:(NSString *)key;
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
- (void)setFloatValue:(float)value forKey:(NSString *)key;
+ (void)setObjectValue:(id)value forKey:(NSString *)key;
+ (void)setIntValue:(int)value forKey:(NSString *)key;
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
+ (void)setFloatValue:(float)value forKey:(NSString *)key;
@end
/**
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
* to delegate methods. If you want these values or the entire object to stay in memory retain
* them or copy them.
**/
@protocol CLSCrashReport <NSObject>
@required
/**
* Returns the session identifier for the crash report.
**/
@property (nonatomic, readonly) NSString *identifier;
/**
* Returns the custom key value data for the crash report.
**/
@property (nonatomic, readonly) NSDictionary *customKeys;
/**
* Returns the CFBundleVersion of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleVersion;
/**
* Returns the CFBundleShortVersionString of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleShortVersionString;
/**
* Returns the date that the application crashed at.
**/
@property (nonatomic, readonly) NSDate *crashedOnDate;
/**
* Returns the os version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSVersion;
/**
* Returns the os build version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSBuildVersion;
@end
/**
*
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
* action on events that occur in the Crashlytics crash reporting system. You can make
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
* or through the convenience startWithAPIKey:delegate:... methods.
*
**/
@protocol CrashlyticsDelegate <NSObject>
@optional
/**
*
* Called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called some time after the crash reporting
* process has begun. If you have specified a delay in one of the
* startWithAPIKey:... calls, this will take at least that long to be invoked.
*
**/
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
/**
*
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
* called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. A CLSCrashReport is passed back that contains data about
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
*
**/
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
@end
/**
* `CrashlyticsKit` can be used as a parameter to `[Fabric with:@[CrashlyticsKit]];` in Objective-C. In Swift, simply use `Crashlytics()`
*/
#define CrashlyticsKit [Crashlytics sharedInstance]
@@ -1,30 +0,0 @@
<?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>English</string>
<key>CFBundleExecutable</key>
<string>Crashlytics</string>
<key>CFBundleIdentifier</key>
<string>com.crashlytics.ios</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Crashlytics</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.10</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>45</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>MinimumOSVersion</key>
<string>4.0</string>
</dict>
</plist>
-1
View File
@@ -1 +0,0 @@
A
BIN
View File
Binary file not shown.
Binary file not shown.
+15
View File
@@ -0,0 +1,15 @@
//
// Double+Yep.swift
// Yep
//
// Created by kevinzhow on 15/5/22.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import Foundation
extension Double {
func format(f: String) -> String {
return NSString(format: "%\(f)f", self) as String
}
}
+24
View File
@@ -130,4 +130,28 @@ extension NSFileManager {
return nil
}
// MARK: Clean Caches
class func cleanCachesDirectoryAtURL(cachesDirectoryURL: NSURL) {
let fileManager = NSFileManager.defaultManager()
if let fileURLs = fileManager.contentsOfDirectoryAtURL(cachesDirectoryURL, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions.allZeros, error: nil) as? [NSURL] {
for fileURL in fileURLs {
fileManager.removeItemAtURL(fileURL, error: nil)
}
}
}
class func cleanAvatarCaches() {
if let avatarCachesURL = yepAvatarCachesURL() {
cleanCachesDirectoryAtURL(avatarCachesURL)
}
}
class func cleanMessageCaches() {
if let messageCachesURL = yepMessageCachesURL() {
cleanCachesDirectoryAtURL(messageCachesURL)
}
}
}
+4
View File
@@ -52,5 +52,9 @@ extension UIColor {
class func yepDisabledColor() -> UIColor {
return UIColor(red:0.95, green:0.95, blue:0.95, alpha:1)
}
class func yepGrayColor() -> UIColor {
return UIColor(red: 142.0/255.0, green: 142.0/255.0, blue: 147.0/255.0, alpha: 1.0)
}
}
+9 -5
View File
@@ -14,22 +14,26 @@ extension UIFont {
}
class func skillTextFont() -> UIFont {
return UIFont(name: "HelveticaNeue-Light", size: 14)!
return UIFont(name: "Helvetica-Light", size: 14)!
}
class func skillTextLargeFont() -> UIFont {
return UIFont(name: "HelveticaNeue-Light", size: 20)!
return UIFont(name: "Helvetica-Light", size: 20)!
}
class func skillHomeTextLargeFont() -> UIFont {
return UIFont(name: "HelveticaNeue-Light", size: 18)!
return UIFont(name: "Helvetica-Light", size: 18)!
}
class func skillHomeButtonFont() -> UIFont {
return UIFont(name: "HelveticaNeue-Light", size: 16)!
return UIFont(name: "Helvetica-Light", size: 16)!
}
class func barButtonFont() -> UIFont {
return UIFont(name: "Helvetica-Light", size: 14)!
}
class func navigationBarTitleFont() -> UIFont {
return UIFont(name: "HelveticaNeue-CondensedBlack", size: 20)!
return UIFont(name: "Helvetica-Bold", size: 15)!
}
}
+17
View File
@@ -50,4 +50,21 @@ class YepAlert {
viewController.presentViewController(alertController, animated: true, completion: nil)
}
class func confirmOrCancel(#title: String, message: String, confirmTitle: String, cancelTitle: String, inViewController viewController: UIViewController, withConfirmAction confirmAction: () -> Void, cancelAction: () -> Void) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let confirmAction: UIAlertAction = UIAlertAction(title: confirmTitle, style: .Default) { action -> Void in
confirmAction()
}
alertController.addAction(confirmAction)
let cancelAction: UIAlertAction = UIAlertAction(title: cancelTitle, style: .Cancel) { action -> Void in
cancelAction()
}
alertController.addAction(cancelAction)
viewController.presentViewController(alertController, animated: true, completion: nil)
}
}
+29 -1
View File
@@ -16,6 +16,9 @@ let introductionKey = "introduction"
let avatarURLStringKey = "avatarURLString"
let pusherIDKey = "pusherID"
let areaCodeKey = "areaCode"
let mobileKey = "mobile"
struct Listener<T>: Hashable {
let name: String
@@ -70,15 +73,22 @@ class YepUserDefaults {
// MARK: ReLogin
class func userNeedRelogin() {
class func cleanAll() {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.removeObjectForKey(v1AccessTokenKey)
defaults.removeObjectForKey(userIDKey)
defaults.removeObjectForKey(nicknameKey)
defaults.removeObjectForKey(introductionKey)
defaults.removeObjectForKey(avatarURLStringKey)
defaults.removeObjectForKey(pusherIDKey)
defaults.removeObjectForKey(areaCodeKey)
defaults.removeObjectForKey(mobileKey)
}
class func userNeedRelogin() {
cleanAll()
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
if let rootViewController = appDelegate.window?.rootViewController {
@@ -199,6 +209,24 @@ class YepUserDefaults {
}
}()
static var areaCode: Listenable<String?> = {
let defaults = NSUserDefaults.standardUserDefaults()
let areaCode = defaults.stringForKey(areaCodeKey)
return Listenable<String?>(areaCode) { areaCode in
defaults.setObject(areaCode, forKey: areaCodeKey)
}
}()
static var mobile: Listenable<String?> = {
let defaults = NSUserDefaults.standardUserDefaults()
let mobile = defaults.stringForKey(mobileKey)
return Listenable<String?>(mobile) { mobile in
defaults.setObject(mobile, forKey: mobileKey)
}
}()
}
+13
View File
@@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon_back.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode",
"template-rendering-intent" : "template"
}
}
Binary file not shown.
@@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon_chat_active_unread.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode",
"template-rendering-intent" : "original"
}
}
@@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon_chat_unread.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode",
"template-rendering-intent" : "original"
}
}
+12
View File
@@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "swipe_up.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.
@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "unread_red_dot.pdf",
"resizing" : {
"mode" : "3-part-horizontal",
"center" : {
"mode" : "fill",
"width" : 1
},
"capInsets" : {
"right" : 7,
"left" : 7
}
}
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.
+15 -1
View File
@@ -19,7 +19,21 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>16</string>
<string>26</string>
<key>Fabric</key>
<dict>
<key>APIKey</key>
<string>3030ba006e21bcf8eb4a2127b6a7931ea6667486</string>
<key>Kits</key>
<array>
<dict>
<key>KitInfo</key>
<dict/>
<key>KitName</key>
<string>Crashlytics</string>
</dict>
</array>
</dict>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
+23
View File
@@ -210,6 +210,12 @@ class Message: Object {
dynamic var conversation: Conversation?
}
class Draft: Object {
dynamic var messageToolbarState: Int = MessageToolbarState.Default.rawValue
dynamic var text: String = ""
}
// MARK: Conversation
enum ConversationType: Int {
@@ -224,6 +230,8 @@ class Conversation: Object {
dynamic var withFriend: User?
dynamic var withGroup: Group?
dynamic var draft: Draft?
var messages: [Message] {
return linkingObjects(Message.self, forProperty: "conversation")
}
@@ -259,6 +267,21 @@ func groupWithGroupID(groupID: String, inRealm realm: Realm) -> Group? {
return realm.objects(Group).filter(predicate).first
}
func countOfUnreadMessagesInRealm(realm: Realm) -> Int {
let predicate = NSPredicate(format: "readed = false AND fromFriend.friendState != %d", UserFriendState.Me.rawValue)
return realm.objects(Message).filter(predicate).count
}
func countOfUnreadMessagesInConversation(conversation: Conversation) -> Int {
return conversation.messages.filter({ message in
if let fromFriend = message.fromFriend {
return (message.readed == false) && (fromFriend.friendState != UserFriendState.Me.rawValue)
} else {
return false
}
}).count
}
func messageWithMessageID(messageID: String, inRealm realm: Realm) -> Message? {
if messageID.isEmpty {
return nil
+24 -40
View File
@@ -73,50 +73,34 @@ class FayeService: NSObject, MZFayeClientDelegate {
client.subscribeToChannel(personalChannel, usingBlock: { data in
// println("subscribeToChannel: \(data)")
let messageInfo = data as! JSONDictionary
if let
messageInfo = data as? JSONDictionary,
messageType = messageInfo["message_type"] as? String {
if let messageType = messageInfo["message_type"] as? String {
switch messageType {
switch messageType {
case FayeService.MessageType.Default.rawValue:
if let messageDataInfo = messageInfo["message"] as? JSONDictionary {
self.saveMessageWithMessageInfo(messageDataInfo)
}
case FayeService.MessageType.Instant.rawValue:
if let messageDataInfo = messageInfo["message"] as? JSONDictionary {
if let
user = messageDataInfo["user"] as? JSONDictionary,
userID = user["id"] as? String,
state = messageDataInfo["state"] as? Int {
var instantStateType = InstantStateType.Text
switch state {
case InstantStateType.Text.rawValue:
instantStateType = .Text
case InstantStateType.Audio.rawValue:
instantStateType = .Audio
// TODO: more InstantStateType
default:
break
}
self.delegate?.fayeRecievedInstantStateType(instantStateType, userID: userID)
case FayeService.MessageType.Default.rawValue:
if let messageDataInfo = messageInfo["message"] as? JSONDictionary {
self.saveMessageWithMessageInfo(messageDataInfo)
}
case FayeService.MessageType.Instant.rawValue:
if let messageDataInfo = messageInfo["message"] as? JSONDictionary {
if let
user = messageDataInfo["user"] as? JSONDictionary,
userID = user["id"] as? String,
state = messageDataInfo["state"] as? Int {
if let instantStateType = InstantStateType(rawValue: state) {
self.delegate?.fayeRecievedInstantStateType(instantStateType, userID: userID)
}
}
}
default:
println("Recieved unknow message type")
}
default:
println("Recieved unknow message type")
}
}
})
+14
View File
@@ -17,6 +17,8 @@ class YepLocationService: NSObject, CLLocationManagerDelegate {
var address:String?
var geocoder = CLGeocoder()
var userLocationUpdated = false
override init() {
super.init()
locationManager.delegate = self
@@ -34,6 +36,18 @@ class YepLocationService: NSObject, CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
if !userLocationUpdated {
updateMyselfWithInfo(["latitude": newLocation.coordinate.latitude, "longitude": newLocation.coordinate.longitude], failureHandler: { (reason, errorMessage) in
defaultFailureHandler(reason, errorMessage)
}, completion: { success in
if success {
self.userLocationUpdated = true
}
})
}
geocoder.reverseGeocodeLocation(newLocation, completionHandler: { (placemarks, error) in
if (error != nil) {println("reverse geodcode fail: \(error.localizedDescription)")}
+101 -85
View File
@@ -225,7 +225,7 @@ func skillsFromSkillsData(skillsData: [JSONDictionary]) -> [Skill] {
let coverURLString = skillInfo["cover_url"] as? String
let skill = Skill(category: skillCategory, id: skillID, name: skillName, localName: skillName, coverURLString: coverURLString)
let skill = Skill(category: skillCategory, id: skillID, name: skillName, localName: skillLocalName, coverURLString: coverURLString)
skills.append(skill)
}
@@ -361,54 +361,30 @@ func updateMyselfWithInfo(info: JSONDictionary, #failureHandler: ((Reason, Strin
}
}
func sendVerifyCode(ofMobile mobile: String, withAreaCode areaCode: String, #failureHandler: ((Reason, String?) -> Void)?, #completion: Bool -> Void) {
let requestParameters = [
"mobile": mobile,
"phone_code": areaCode,
]
let parse: JSONDictionary -> Bool? = { data in
if let status = data["status"] as? String {
if status == "sms sent" {
return true
}
}
return false
}
let resource = jsonResource(path: "/api/v1/auth/send_verify_code", method: .POST, requestParameters: requestParameters, parse: parse)
if let failureHandler = failureHandler {
apiRequest({_ in}, baseURL, resource, failureHandler, completion)
} else {
apiRequest({_ in}, baseURL, resource, defaultFailureHandler, completion)
}
enum VerifyCodeMethod: String {
case SMS = "sms"
case Call = "call"
}
func resendVoiceVerifyCode(ofMobile mobile: String, withAreaCode areaCode: String, #failureHandler: ((Reason, String?) -> Void)?, #completion: Bool -> Void) {
func sendVerifyCodeOfMobile(mobile: String, withAreaCode areaCode: String, useMethod method: VerifyCodeMethod, #failureHandler: ((Reason, String?) -> Void)?, #completion: Bool -> Void) {
let requestParameters = [
"mobile": mobile,
"phone_code": areaCode,
"method": method.rawValue
]
let parse: JSONDictionary -> Bool? = { data in
if let status = data["state"] as? String {
return true
}
return false
return true
}
let resource = jsonResource(path: "/api/v1/registration/resend_verify_code_by_voice", method: .POST, requestParameters: requestParameters, parse: parse)
let resource = jsonResource(path: "/api/v1/sms_verification_codes", method: .POST, requestParameters: requestParameters, parse: parse)
if let failureHandler = failureHandler {
apiRequest({_ in}, baseURL, resource, failureHandler, completion)
} else {
apiRequest({_ in}, baseURL, resource, defaultFailureHandler, completion)
}
}
func loginByMobile(mobile: String, withAreaCode areaCode: String, #verifyCode: String, #failureHandler: ((Reason, String?) -> Void)?, #completion: LoginUser -> Void) {
@@ -512,6 +488,18 @@ private func moreFriendships(inPage page: Int, withPerPage perPage: Int, #failur
enum DiscoveredUserSortStyle: String {
case Distance = "distance"
case LastSignIn = "last_sign_in_at"
case Default = "default"
var name: String {
switch self {
case .Distance:
return NSLocalizedString("Nearby", comment: "")
case .LastSignIn:
return NSLocalizedString("Time", comment: "")
case .Default:
return NSLocalizedString("Default", comment: "")
}
}
}
struct DiscoveredUser {
@@ -539,6 +527,57 @@ struct DiscoveredUser {
let socialAccountProviders: [SocialAccountProvider]
}
let parseDiscoveredUsers: JSONDictionary -> [DiscoveredUser]? = { data in
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)
}
}
return discoveredUsers
}
return nil
}
func discoverUsers(#masterSkills: [String], #learningSkills: [String], #discoveredUserSortStyle: DiscoveredUserSortStyle, #failureHandler: ((Reason, String?) -> Void)?, #completion: [DiscoveredUser] -> Void) {
let requestParameters:[String: AnyObject] = [
@@ -547,55 +586,7 @@ func discoverUsers(#masterSkills: [String], #learningSkills: [String], #discover
"sort": discoveredUserSortStyle.rawValue
]
let parse: JSONDictionary -> [DiscoveredUser]? = { data in
//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)
}
}
return discoveredUsers
}
return nil
}
let parse = parseDiscoveredUsers
let resource = authJsonResource(path: "/api/v1/user/discover", method: .GET, requestParameters: requestParameters as JSONDictionary, parse: parse)
@@ -606,6 +597,23 @@ func discoverUsers(#masterSkills: [String], #learningSkills: [String], #discover
}
}
func searchUsersByQ(q: String, #failureHandler: ((Reason, String?) -> Void)?, #completion: [DiscoveredUser] -> Void) {
let requestParameters = [
"q": q
]
let parse = parseDiscoveredUsers
let resource = authJsonResource(path: "/api/v1/users/search", method: .GET, requestParameters: requestParameters, parse: parse)
if let failureHandler = failureHandler {
apiRequest({_ in}, baseURL, resource, failureHandler, completion)
} else {
apiRequest({_ in}, baseURL, resource, defaultFailureHandler, completion)
}
}
func friendships(#completion: [JSONDictionary] -> Void) {
headFriendships { result in
@@ -835,6 +843,7 @@ func createMessageWithMessageInfo(messageInfo: JSONDictionary, #failureHandler:
FayeService.sharedManager.sendGroupMessage(messageInfo, circleID: recipientID, completion: { (success, messageID) in
if success, let messageID = messageID {
completion(messageID: messageID)
} else {
@@ -850,14 +859,21 @@ func createMessageWithMessageInfo(messageInfo: JSONDictionary, #failureHandler:
FayeService.sharedManager.sendPrivateMessage(messageInfo, messageType: .Default, userID: recipientID, completion: { (success, messageID) in
if success, let messageID = messageID {
println("Mesasge id is \(messageID)")
completion(messageID: messageID)
} else {
if let failureHandler = failureHandler {
failureHandler(Reason.CouldNotParseJSON, "Faye Created Message Error")
if success {
println("Mesasgeing packge without message id")
} else {
defaultFailureHandler(Reason.CouldNotParseJSON, "Faye Created Message Error")
if let failureHandler = failureHandler {
failureHandler(Reason.CouldNotParseJSON, "Faye Created Message Error")
} else {
defaultFailureHandler(Reason.CouldNotParseJSON, "Faye Created Message Error")
}
}
}
})
+205 -28
View File
@@ -15,24 +15,22 @@ let YepNewMessagesReceivedNotification = "YepNewMessagesReceivedNotification"
func downloadAttachmentOfMessage(message: Message) {
func updateAttachmentOfMessage(message: Message, withAttachmentFileName attachmentFileName: String) {
if let realm = message.realm {
realm.beginWrite()
func updateAttachmentOfMessage(message: Message, withAttachmentFileName attachmentFileName: String, inRealm realm: Realm) {
realm.write {
message.localAttachmentName = attachmentFileName
message.downloadState = MessageDownloadState.Downloaded.rawValue
realm.commitWrite()
}
}
func updateThumbnailOfMessage(message: Message, withThumbnailFileName thumbnailFileName: String) {
if let realm = message.realm {
realm.beginWrite()
func updateThumbnailOfMessage(message: Message, withThumbnailFileName thumbnailFileName: String, inRealm realm: Realm) {
realm.write {
message.localThumbnailName = thumbnailFileName
realm.commitWrite()
}
}
let messageID = message.messageID
let attachmentURLString = message.attachmentURLString
let mediaType = message.mediaType
if !attachmentURLString.isEmpty && message.downloadState != MessageDownloadState.Downloaded.rawValue {
if let url = NSURL(string: attachmentURLString) {
@@ -43,24 +41,30 @@ func downloadAttachmentOfMessage(message: Message) {
let fileName = NSUUID().UUIDString
dispatch_async(dispatch_get_main_queue()) {
switch message.mediaType {
case MessageMediaType.Image.rawValue:
if let fileURL = NSFileManager.saveMessageImageData(data, withName: fileName) {
updateAttachmentOfMessage(message, withAttachmentFileName: fileName)
}
case MessageMediaType.Video.rawValue:
if let fileURL = NSFileManager.saveMessageVideoData(data, withName: fileName) {
updateAttachmentOfMessage(message, withAttachmentFileName: fileName)
}
case MessageMediaType.Audio.rawValue:
if let fileURL = NSFileManager.saveMessageAudioData(data, withName: fileName) {
updateAttachmentOfMessage(message, withAttachmentFileName: fileName)
}
let realm = Realm()
if let message = messageWithMessageID(messageID, inRealm: realm) {
default:
break
switch mediaType {
case MessageMediaType.Image.rawValue:
if let fileURL = NSFileManager.saveMessageImageData(data, withName: fileName) {
updateAttachmentOfMessage(message, withAttachmentFileName: fileName, inRealm: realm)
}
case MessageMediaType.Video.rawValue:
if let fileURL = NSFileManager.saveMessageVideoData(data, withName: fileName) {
updateAttachmentOfMessage(message, withAttachmentFileName: fileName, inRealm: realm)
}
case MessageMediaType.Audio.rawValue:
if let fileURL = NSFileManager.saveMessageAudioData(data, withName: fileName) {
updateAttachmentOfMessage(message, withAttachmentFileName: fileName, inRealm: realm)
}
default:
break
}
}
}
}
@@ -68,12 +72,15 @@ func downloadAttachmentOfMessage(message: Message) {
}
}
if message.mediaType == MessageMediaType.Video.rawValue {
if mediaType == MessageMediaType.Video.rawValue {
let thumbnailURLString = message.thumbnailURLString
if !thumbnailURLString.isEmpty && message.localThumbnailName.isEmpty {
if let url = NSURL(string: thumbnailURLString) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let data = NSData(contentsOfURL: url)
if let data = data {
@@ -81,8 +88,12 @@ func downloadAttachmentOfMessage(message: Message) {
dispatch_async(dispatch_get_main_queue()) {
if let fileURL = NSFileManager.saveMessageImageData(data, withName: fileName) {
updateThumbnailOfMessage(message, withThumbnailFileName: fileName)
let realm = Realm()
if let message = messageWithMessageID(messageID, inRealm: realm) {
if let fileURL = NSFileManager.saveMessageImageData(data, withName: fileName) {
updateThumbnailOfMessage(message, withThumbnailFileName: fileName, inRealm: realm)
}
}
}
}
@@ -93,6 +104,86 @@ func downloadAttachmentOfMessage(message: Message) {
}
func skillsFromUserSkillList(userSkillList: List<UserSkill>) -> [Skill] {
var userSkills = [UserSkill]()
for userSkill in userSkillList {
userSkills.append(userSkill)
}
return userSkills.map({ userSkill -> Skill? in
if let category = userSkill.category {
let skillCategory = SkillCategory(id: category.skillCategoryID, name: category.name, localName: category.localName, skills: [])
let skill = Skill(category: skillCategory, id: userSkill.skillID, name: userSkill.name, localName: userSkill.localName, coverURLString: userSkill.coverURLString)
return skill
}
return nil
}).filter({ $0 != nil }).map({ skill in skill! })
}
func userSkillsFromSkills(skills: [Skill], inRealm realm: Realm) -> [UserSkill] {
return skills.map({ skill -> UserSkill? in
let skillID = skill.id
var userSkill = userSkillWithSkillID(skillID, inRealm: realm)
if userSkill == nil {
let newUserSkill = UserSkill()
newUserSkill.skillID = skillID
newUserSkill.name = skillID
newUserSkill.localName = skill.localName
if let coverURLString = skill.coverURLString {
newUserSkill.coverURLString = coverURLString
}
realm.add(newUserSkill)
userSkill = newUserSkill
}
if let userSkill = userSkill {
if let skillCategory = skill.category, skillCategoryID = skill.category?.id {
var userSkillCategory = userSkillCategoryWithSkillCategoryID(skillCategoryID, inRealm: realm)
if userSkillCategory == nil {
let newUserSkillCategory = UserSkillCategory()
newUserSkillCategory.skillCategoryID = skillCategoryID
newUserSkillCategory.name = skillCategory.name
newUserSkillCategory.localName = skillCategory.localName
realm.add(newUserSkillCategory)
userSkillCategory = newUserSkillCategory
}
if let userSkillCategory = userSkillCategory {
userSkill.category = userSkillCategory
}
}
}
return userSkill
}).filter({ $0 != nil }).map({ skill in skill! })
}
func userSocialAccountProvidersFromSocialAccountProviders(socialAccountProviders: [DiscoveredUser.SocialAccountProvider]) -> [UserSocialAccountProvider] {
return socialAccountProviders.map({ _provider -> UserSocialAccountProvider in
let provider = UserSocialAccountProvider()
provider.name = _provider.name
provider.enabled = _provider.enabled
return provider
})
}
func userSkillsFromSkillsData(skillsData: [JSONDictionary], inRealm realm: Realm) -> [UserSkill] {
var userSkills = [UserSkill]()
@@ -153,6 +244,92 @@ func userSkillsFromSkillsData(skillsData: [JSONDictionary], inRealm realm: Realm
return userSkills
}
func syncMyInfoAndDoFurtherAction(furtherAction: () -> Void) {
userInfo(failureHandler: nil) { friendInfo in
println("my userInfo: \(friendInfo)")
furtherAction()
if let myUserID = YepUserDefaults.userID.value {
let realm = Realm()
var me = userWithUserID(myUserID, inRealm: realm)
if me == nil {
let newUser = User()
newUser.userID = myUserID
newUser.friendState = UserFriendState.Me.rawValue
if let createdAtString = friendInfo["created_at"] as? String {
newUser.createdAt = NSDate.dateWithISO08601String(createdAtString)
}
realm.beginWrite()
realm.add(newUser)
realm.commitWrite()
me = newUser
}
if let user = me {
realm.beginWrite()
//
if let lastSignInAtString = friendInfo["last_sign_in_at"] as? String {
user.lastSignInAt = NSDate.dateWithISO08601String(lastSignInAtString)
}
if let nickname = friendInfo["nickname"] as? String {
user.nickname = nickname
}
if let introduction = friendInfo["introduction"] as? String {
user.introduction = introduction
}
if let avatarURLString = friendInfo["avatar_url"] as? String {
user.avatarURLString = avatarURLString
}
//
if let learningSkillsData = friendInfo["learning_skills"] as? [JSONDictionary] {
user.learningSkills.removeAll()
let userSkills = userSkillsFromSkillsData(learningSkillsData, inRealm: realm)
user.learningSkills.extend(userSkills)
}
if let masterSkillsData = friendInfo["master_skills"] as? [JSONDictionary] {
user.masterSkills.removeAll()
let userSkills = userSkillsFromSkillsData(masterSkillsData, inRealm: realm)
user.masterSkills.extend(userSkills)
}
// Social Account Provider
user.socialAccountProviders.removeAll()
if let providersInfo = friendInfo["providers"] as? [String: Bool] {
for (name, enabled) in providersInfo {
let provider = UserSocialAccountProvider()
provider.name = name
provider.enabled = enabled
user.socialAccountProviders.append(provider)
}
}
realm.commitWrite()
}
}
}
}
func syncFriendshipsAndDoFurtherAction(furtherAction: () -> Void) {
friendships { allFriendships in
//println("\n allFriendships: \(allFriendships)")
@@ -0,0 +1,138 @@
//
// AddFriendsViewController.swift
// Yep
//
// Created by NIX on 15/5/19.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
class AddFriendsViewController: UIViewController {
@IBOutlet weak var addFriendsTableView: UITableView!
let addFriendSearchCellIdentifier = "AddFriendSearchCell"
let addFriendMoreCellIdentifier = "AddFriendMoreCell"
override func viewDidLoad() {
super.viewDidLoad()
title = NSLocalizedString("Add Friends", comment: "")
addFriendsTableView.rowHeight = 60
addFriendsTableView.registerNib(UINib(nibName: addFriendSearchCellIdentifier, bundle: nil), forCellReuseIdentifier: addFriendSearchCellIdentifier)
addFriendsTableView.registerNib(UINib(nibName: addFriendMoreCellIdentifier, bundle: nil), forCellReuseIdentifier: addFriendMoreCellIdentifier)
}
// MARK: Actions
@IBAction func done(sender: UIBarButtonItem) {
dismissViewControllerAnimated(true, completion: nil)
// TODO: done add friend
}
// MARK: Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showSearchedUsers" {
if let mobile = sender as? String {
let vc = segue.destinationViewController as! SearchedUsersViewController
vc.mobile = mobile
}
}
}
}
extension AddFriendsViewController: UITableViewDataSource, UITableViewDelegate {
enum Section: Int {
case Search = 0
case More
static var caseCount: Int {
var max: Int = 0
while let _ = self(rawValue: ++max) {}
return max
}
}
enum More: Int, Printable {
case Contacts
case FaceToFace
static var caseCount: Int {
var max: Int = 0
while let _ = self(rawValue: ++max) {}
return max
}
var description: String {
switch self {
case .Contacts:
return NSLocalizedString("Friends in Contacts", comment: "")
case .FaceToFace:
return NSLocalizedString("Face to Face", comment: "")
}
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return Section.caseCount
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case Section.Search.rawValue:
return 1
case Section.More.rawValue:
return More.caseCount
default:
return 0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.section {
case Section.Search.rawValue:
let cell = tableView.dequeueReusableCellWithIdentifier(addFriendSearchCellIdentifier) as! AddFriendSearchCell
cell.searchTextField.returnKeyType = .Search
cell.searchTextField.delegate = self
return cell
case Section.More.rawValue:
let cell = tableView.dequeueReusableCellWithIdentifier(addFriendMoreCellIdentifier) as! AddFriendMoreCell
cell.annotationLabel.text = More(rawValue: indexPath.row)?.description
return cell
default:
return UITableViewCell()
}
}
}
extension AddFriendsViewController: UITextFieldDelegate {
func textFieldShouldReturn(textField: UITextField) -> Bool {
let text = textField.text
textField.resignFirstResponder()
performSegueWithIdentifier("showSearchedUsers", sender: text)
return true
}
}
@@ -0,0 +1,63 @@
//
// BaseViewController.swift
// Yep
//
// Created by kevinzhow on 15/5/23.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
class BaseViewController: UIViewController {
var animatedOnNavigationBar = true
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let navigationController = navigationController {
navigationController.navigationBar.backgroundColor = nil
navigationController.navigationBar.translucent = true
navigationController.navigationBar.shadowImage = nil
navigationController.navigationBar.barStyle = UIBarStyle.Default
navigationController.navigationBar.setBackgroundImage(nil, forBarMetrics: UIBarMetrics.Default)
let textAttributes = [
NSForegroundColorAttributeName: UIColor.yepTintColor(),
NSFontAttributeName: UIFont.navigationBarTitleFont()
]
navigationController.navigationBar.titleTextAttributes = textAttributes
navigationController.navigationBar.tintColor = nil
}
if let hidden = self.navigationController?.navigationBarHidden {
if hidden {
self.navigationController?.setNavigationBarHidden(false, animated: animatedOnNavigationBar)
}
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
@@ -9,7 +9,7 @@
import UIKit
import RealmSwift
class ContactsViewController: UIViewController {
class ContactsViewController: BaseViewController {
@IBOutlet weak var contactsTableView: UITableView!
@@ -20,6 +20,7 @@ class ContactsViewController: UIViewController {
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
@@ -40,6 +41,12 @@ class ContactsViewController: UIViewController {
contactsTableView.reloadData()
}
// MARK: Actions
@IBAction func presentAddFriends(sender: UIBarButtonItem) {
performSegueWithIdentifier("presentAddFriends", sender: nil)
}
// MARK: Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
@@ -47,10 +54,14 @@ class ContactsViewController: UIViewController {
let vc = segue.destinationViewController as! ProfileViewController
if let user = sender as? User {
vc.profileUser = ProfileUser.UserType(user)
if user.userID != YepUserDefaults.userID.value {
vc.profileUser = ProfileUser.UserType(user)
}
}
vc.hidesBottomBarWhenPushed = true
vc.setBackButtonWithTitle()
}
}
}
@@ -74,7 +85,7 @@ extension ContactsViewController: UITableViewDataSource, UITableViewDelegate {
}
cell.nameLabel.text = friend.nickname
cell.joinedDateLabel.text = friend.createdAt.timeAgo
cell.joinedDateLabel.text = friend.introduction
cell.lastTimeSeenLabel.text = friend.createdAt.timeAgo
return cell
@@ -0,0 +1,205 @@
//
// ConversationMessagePreviewNavigationControllerDelegate.swift
// Yep
//
// Created by NIX on 15/5/25.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
class ConversationMessagePreviewNavigationControllerDelegate: NSObject, UINavigationControllerDelegate, UIViewControllerAnimatedTransitioning {
// MARK: UINavigationControllerDelegate
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if operation == .Push {
if fromVC.isKindOfClass(ConversationViewController.self) && toVC.isKindOfClass(MessageMediaViewController.self) {
isPresentation = true
return self
}
} else if operation == .Pop {
if fromVC.isKindOfClass(MessageMediaViewController.self) && toVC.isKindOfClass(ConversationViewController.self) {
isPresentation = false
return self
}
}
return nil
}
// MARK: UIViewControllerAnimatedTransitioning
var frame = CGRectZero
var transitionView: UIView? {
didSet {
if let transitionView = transitionView {
transitionViewSnapshot = transitionView.snapshotViewAfterScreenUpdates(false)
}
}
}
var transitionViewSnapshot: UIView?
var isPresentation = true
var transitionContext: UIViewControllerContextTransitioning?
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return isPresentation ? 0.5 : 0.5
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
self.transitionContext = transitionContext
if isPresentation {
presentTransition(transitionContext)
} else {
dismissTransition(transitionContext)
}
}
let largerOffset: CGFloat = 80
func presentTransition(transitionContext: UIViewControllerContextTransitioning) {
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? ConversationsViewController
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as? MessageMediaViewController
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)
let containerView = transitionContext.containerView()
containerView.addSubview(toView!)
let animatingVC = toVC!
let animatingView = toView!
if let transitionViewSnapshot = transitionViewSnapshot {
animatingView.addSubview(transitionViewSnapshot)
transitionViewSnapshot.frame = frame
animatingVC.view.backgroundColor = UIColor.clearColor()
animatingVC.mediaView.alpha = 0
animatingVC.mediaControlView.alpha = 0
let fullDuration = transitionDuration(transitionContext)
UIView.animateKeyframesWithDuration(fullDuration, delay: 0.0, options: .CalculationModeCubic, animations: { () -> Void in
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: fullDuration, animations: { () -> Void in
animatingVC.view.backgroundColor = UIColor.blackColor()
})
UIView.addKeyframeWithRelativeStartTime(0.2, relativeDuration: 0.5, animations: { () -> Void in
transitionViewSnapshot.center = animatingView.center
})
UIView.addKeyframeWithRelativeStartTime(0.7, relativeDuration: 0.2, animations: { () -> Void in
let targetWidth = animatingView.bounds.width + self.largerOffset
let dw = targetWidth - transitionViewSnapshot.bounds.width
let ratio = targetWidth / transitionViewSnapshot.bounds.width
let height = ratio * transitionViewSnapshot.bounds.height
let dh = height - transitionViewSnapshot.bounds.height
let frame = CGRectInset(transitionViewSnapshot.frame, -dw * 0.5, -dh * 0.5)
transitionViewSnapshot.frame = frame
})
UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.0, animations: { () -> Void in
let ratio = (animatingView.bounds.width + self.largerOffset) / animatingView.bounds.width
animatingVC.mediaView.transform = CGAffineTransformMakeScale(ratio, ratio)
animatingVC.mediaView.alpha = 1
animatingVC.mediaControlView.alpha = 1
transitionViewSnapshot.alpha = 0
})
UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.1, animations: { () -> Void in
animatingVC.mediaView.transform = CGAffineTransformMakeScale(1.0, 1.0)
})
}, completion: { (finished) -> Void in
transitionViewSnapshot.removeFromSuperview()
transitionContext.completeTransition(true)
})
} else {
transitionContext.completeTransition(false)
}
}
func dismissTransition(transitionContext: UIViewControllerContextTransitioning) {
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? MessageMediaViewController
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)
let containerView = transitionContext.containerView()
containerView.addSubview(toView!)
containerView.addSubview(fromView!)
let animatingVC = fromVC!
let animatingView = fromView!
let fullDuration = transitionDuration(transitionContext)
if let transitionViewSnapshot = transitionViewSnapshot {
if let transitionView = self.transitionView {
transitionView.alpha = 0
}
UIView.animateKeyframesWithDuration(fullDuration, delay: 0.0, options: .CalculationModeCubic, animations: { () -> Void in
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: fullDuration, animations: { () -> Void in
animatingVC.view.backgroundColor = UIColor.clearColor()
})
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.2, animations: { () -> Void in
let ratio = (animatingView.bounds.width + self.largerOffset) / animatingView.bounds.width
animatingVC.mediaView.transform = CGAffineTransformMakeScale(ratio, ratio)
animatingVC.mediaControlView.alpha = 0
})
UIView.addKeyframeWithRelativeStartTime(0.2, relativeDuration: 0.0, animations: { () -> Void in
animatingView.addSubview(transitionViewSnapshot)
transitionViewSnapshot.center = animatingView.center
transitionViewSnapshot.alpha = 1
animatingVC.mediaView.alpha = 0
})
UIView.addKeyframeWithRelativeStartTime(0.2, relativeDuration: 0.6, animations: { () -> Void in
transitionViewSnapshot.frame = self.frame
})
}, completion: { (finished) -> Void in
if let transitionView = self.transitionView {
transitionView.alpha = 1
}
transitionViewSnapshot.removeFromSuperview()
transitionContext.completeTransition(true)
})
} else {
transitionContext.completeTransition(false)
}
}
}
@@ -11,8 +11,10 @@ import RealmSwift
import AVFoundation
import MobileCoreServices
class ConversationViewController: UIViewController {
class ConversationViewController: BaseViewController {
@IBOutlet weak var swipeUpView: UIView!
struct Notification {
static let MessageSent = "MessageSentNotification"
}
@@ -46,6 +48,7 @@ class ConversationViewController: UIViewController {
}()
var messagePreviewTransitionManager: ConversationMessagePreviewTransitionManager?
var navigationControllerDelegate: ConversationMessagePreviewNavigationControllerDelegate?
var conversationCollectionViewHasBeenMovedToBottomOnce = false
@@ -74,10 +77,15 @@ class ConversationViewController: UIViewController {
lazy var titleView: ConversationTitleView = {
let titleView = ConversationTitleView(frame: CGRect(origin: CGPointZero, size: CGSize(width: 150, height: 44)))
titleView.nameLabel.text = nameOfConversation(self.conversation)
let name = nameOfConversation(self.conversation)
titleView.nameLabel.text = name
self.updateStateInfoOfTitleView(titleView)
self.navigationItem.title = name
return titleView
}()
@@ -160,13 +168,15 @@ class ConversationViewController: UIViewController {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.swipeUpView.hidden = true
realm = Realm()
navigationController?.interactivePopGestureRecognizer.delaysTouchesBegan = false
// navigationController?.interactivePopGestureRecognizer.delegate = self
if messages.count >= messagesBunchCount {
displayedMessagesRange = NSRange(location: Int(messages.count) - messagesBunchCount, length: messagesBunchCount)
@@ -283,8 +293,10 @@ class ConversationViewController: UIViewController {
// MARK: Audio Send
messageToolbar.voiceSendBeginAction = { messageToolbar in
self.view.window?.addSubview(self.waverView)
self.view.addSubview(self.waverView)
self.swipeUpView.hidden = false
self.view.bringSubviewToFront(self.swipeUpView)
let audioFileName = NSUUID().UUIDString
self.waverView.waver.resetWaveSamples()
@@ -304,11 +316,13 @@ class ConversationViewController: UIViewController {
}
messageToolbar.voiceSendCancelAction = { messageToolbar in
self.swipeUpView.hidden = true
self.waverView.removeFromSuperview()
YepAudioService.sharedManager.endRecord()
}
messageToolbar.voiceSendEndAction = { messageToolbar in
self.swipeUpView.hidden = true
self.waverView.removeFromSuperview()
if YepAudioService.sharedManager.audioRecorder?.currentTime < 0.5 {
YepAudioService.sharedManager.endRecord()
@@ -406,13 +420,15 @@ class ConversationViewController: UIViewController {
// MARK: MessageToolbar State Transitions
messageToolbar.stateTransitionAction = { (previousState, currentState) in
messageToolbar.stateTransitionAction = { (messageToolbar, previousState, currentState) in
switch (previousState, currentState) {
case (.MoreMessages, .Default):
if !self.isKeyboardVisible {
self.adjustBackCollectionViewWithHeight(0, animationDuration: 0.3, animationCurveValue: 7)
}else{
} else {
self.hideKeyboardAndShowMoreMessageView()
}
@@ -421,6 +437,30 @@ class ConversationViewController: UIViewController {
self.hideKeyboardAndShowMoreMessageView()
}
}
// 稿
let realm = Realm()
if let draft = self.conversation.draft {
realm.write {
draft.messageToolbarState = currentState.rawValue
if currentState == .TextInputing {
draft.text = messageToolbar.messageTextView.text
}
}
} else {
let draft = Draft()
draft.messageToolbarState = currentState.rawValue
realm.write {
self.conversation.draft = draft
}
}
}
@@ -455,6 +495,24 @@ class ConversationViewController: UIViewController {
addLocationButton.tapAction = {
self.performSegueWithIdentifier("presentPickLocation", sender: nil)
}
}
func prepareTextInputView() {
// messageToolbar
if let
draft = conversation.draft,
state = MessageToolbarState(rawValue: draft.messageToolbarState) {
if state == .TextInputing {
messageToolbar.messageTextView.text = draft.text
// messageToolbar.messageTextView.becomeFirstResponder()
}
//
messageToolbar.state = state
}
}
override func viewDidAppear(animated: Bool) {
@@ -477,6 +535,7 @@ class ConversationViewController: UIViewController {
})
}
}
}
override func viewDidDisappear(animated: Bool) {
@@ -505,6 +564,7 @@ class ConversationViewController: UIViewController {
//
scrollToLastMessage()
prepareTextInputView()
}
self.waverView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - self.messageToolbar.frame.size.height)
@@ -853,6 +913,53 @@ class ConversationViewController: UIViewController {
}
}
func playMessageAudioWithMessage(message: Message?) {
if let audioPlayer = YepAudioService.sharedManager.audioPlayer {
if let playingMessage = YepAudioService.sharedManager.playingMessage {
if audioPlayer.playing {
audioPlayer.pause()
if let playbackTimer = YepAudioService.sharedManager.playbackTimer {
playbackTimer.invalidate()
}
if let sender = playingMessage.fromFriend, playingMessageIndex = messages.indexOf(playingMessage) {
let indexPath = NSIndexPath(forItem: playingMessageIndex - displayedMessagesRange.location, inSection: 0)
if sender.friendState != UserFriendState.Me.rawValue {
if let cell = conversationCollectionView.cellForItemAtIndexPath(indexPath) as? ChatLeftAudioCell {
cell.playing = false
}
} else {
if let cell = conversationCollectionView.cellForItemAtIndexPath(indexPath) as? ChatRightAudioCell {
cell.playing = false
}
}
}
if let message = message {
if message.messageID == playingMessage.messageID {
return
}
}
}
}
}
if let message = message {
let audioPlayedDuration = audioPlayedDurationOfMessage(message) as NSTimeInterval
YepAudioService.sharedManager.playAudioWithMessage(message, beginFromTime: audioPlayedDuration, delegate: self) {
let playbackTimer = NSTimer.scheduledTimerWithTimeInterval(0.02, target: self, selector: "updateAudioPlaybackProgress:", userInfo: nil, repeats: true)
YepAudioService.sharedManager.playbackTimer = playbackTimer
}
}
}
// MARK: Keyboard
func handleKeyboardWillShowNotification(notification: NSNotification) {
@@ -944,29 +1051,32 @@ class ConversationViewController: UIViewController {
func adjustBackCollectionViewWithHeight(newHeight: CGFloat, animationDuration: NSTimeInterval, animationCurveValue: UInt) {
self.conversationCollectionViewContentOffsetBeforeKeyboardWillShow = CGPointZero
if (conversationCollectionViewContentOffsetBeforeKeyboardWillHide == CGPointZero) {
conversationCollectionViewContentOffsetBeforeKeyboardWillHide = conversationCollectionView.contentOffset
}
UIView.animateWithDuration(animationDuration, delay: 0, options: UIViewAnimationOptions(animationCurveValue << 16), animations: { () -> Void in
var contentOffset = self.conversationCollectionViewContentOffsetBeforeKeyboardWillHide
self.messageToolbarBottomConstraint.constant = 0
if self.messageToolbar.state != .MoreMessages {
contentOffset.y -= newHeight
}else {
} else {
contentOffset.y -= (newHeight - self.moreMessageTypesViewHeightConstraintConstant)
}
//println("\(self.conversationCollectionViewContentOffsetBeforeKeyboardWillHide.y) \(contentOffset.y) \(self.conversationCollectionViewContentOffsetBeforeKeyboardWillHide.y-contentOffset.y)")
self.conversationCollectionView.setContentOffset(contentOffset, animated: false)
self.conversationCollectionView.contentInset.bottom = CGRectGetHeight(self.messageToolbar.bounds)
self.view.layoutIfNeeded()
}, completion: { (finished) -> Void in
}, completion: { (finished) -> Void in
})
}
func handleKeyboardDidHideNotification(notification: NSNotification) {
@@ -982,13 +1092,97 @@ class ConversationViewController: UIViewController {
let vc = segue.destinationViewController as! ProfileViewController
if let withFriend = conversation?.withFriend {
let profileUser = ProfileUser.UserType(withFriend)
vc.profileUser = profileUser
if withFriend.userID != YepUserDefaults.userID.value {
vc.profileUser = ProfileUser.UserType(withFriend)
}
vc.isFromConversation = true
vc.setBackButtonWithTitle()
}
}
if segue.identifier == "presentMessageMedia" {
} else if segue.identifier == "showMessageMedia" {
let vc = segue.destinationViewController as! MessageMediaViewController
if let message = sender as? Message, messageIndex = messages.indexOf(message) {
vc.message = message
let indexPath = NSIndexPath(forRow: messageIndex - displayedMessagesRange.location , inSection: 0)
if let cell = conversationCollectionView.cellForItemAtIndexPath(indexPath) {
var frame = CGRectZero
var transitionView: UIView?
if let sender = message.fromFriend {
if sender.friendState != UserFriendState.Me.rawValue {
switch message.mediaType {
case MessageMediaType.Image.rawValue:
let cell = cell as! ChatLeftImageCell
transitionView = cell.messageImageView
frame = cell.convertRect(cell.messageImageView.frame, toView: view)
case MessageMediaType.Video.rawValue:
let cell = cell as! ChatLeftVideoCell
transitionView = cell.thumbnailImageView
frame = cell.convertRect(cell.thumbnailImageView.frame, toView: view)
case MessageMediaType.Location.rawValue:
let cell = cell as! ChatLeftLocationCell
transitionView = cell.mapImageView
frame = cell.convertRect(cell.mapImageView.frame, toView: view)
default:
break
}
} else {
switch message.mediaType {
case MessageMediaType.Image.rawValue:
let cell = cell as! ChatRightImageCell
transitionView = cell.messageImageView
frame = cell.convertRect(cell.messageImageView.frame, toView: view)
case MessageMediaType.Video.rawValue:
let cell = cell as! ChatRightVideoCell
transitionView = cell.thumbnailImageView
frame = cell.convertRect(cell.thumbnailImageView.frame, toView: view)
case MessageMediaType.Location.rawValue:
let cell = cell as! ChatRightLocationCell
transitionView = cell.mapImageView
frame = cell.convertRect(cell.mapImageView.frame, toView: view)
default:
break
}
}
}
// vc.modalPresentationStyle = UIModalPresentationStyle.Custom
//
// let transitionManager = ConversationMessagePreviewTransitionManager()
// transitionManager.frame = frame
// transitionManager.transitionView = transitionView
//
// vc.transitioningDelegate = transitionManager
//
// messagePreviewTransitionManager = transitionManager
let delegate = ConversationMessagePreviewNavigationControllerDelegate()
delegate.frame = frame
delegate.transitionView = transitionView
navigationControllerDelegate = delegate
navigationController?.delegate = delegate
}
}
} else if segue.identifier == "presentMessageMedia" {
let vc = segue.destinationViewController as! MessageMediaViewController
@@ -1106,6 +1300,28 @@ class ConversationViewController: UIViewController {
}
}
}
}
// MARK: UIGestureRecognizerDelegate
extension ConversationViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let isAnimated = navigationController?.transitionCoordinator()?.isAnimated() {
return !isAnimated
}
if navigationController?.viewControllers.count < 2 {
return false
}
if gestureRecognizer == navigationController?.interactivePopGestureRecognizer {
return true
}
return false
}
}
// MARK: UICollectionViewDataSource, UICollectionViewDelegate
@@ -1143,16 +1359,19 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
// TODO: mark as read mark as read
downloadAttachmentOfMessage(message)
markAsReadMessage(message, failureHandler: nil) { success in
dispatch_async(dispatch_get_main_queue()) {
let realm = Realm()
if let message = messageWithMessageID(message.messageID, inRealm: realm) {
realm.write {
message.readed = true
}
//
if navigationController?.topViewController == self {
markAsReadMessage(message, failureHandler: nil) { success in
dispatch_async(dispatch_get_main_queue()) {
let realm = Realm()
println("\(message.messageID) mark as read")
if let message = messageWithMessageID(message.messageID, inRealm: realm) {
realm.write {
message.readed = true
}
println("\(message.messageID) mark as read")
}
}
}
}
@@ -1161,7 +1380,10 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
case MessageMediaType.Image.rawValue:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftImageCellIdentifier, forIndexPath: indexPath) as! ChatLeftImageCell
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio)
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: {
self.performSegueWithIdentifier("showMessageMedia", sender: message)
})
return cell
@@ -1169,14 +1391,21 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftAudioCellIdentifier, forIndexPath: indexPath) as! ChatLeftAudioCell
let audioPlayedDuration = audioPlayedDurationOfMessage(message)
cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration)
cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { message in
self.playMessageAudioWithMessage(message)
})
return cell
case MessageMediaType.Video.rawValue:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftVideoCellIdentifier, forIndexPath: indexPath) as! ChatLeftVideoCell
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio)
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: {
self.performSegueWithIdentifier("showMessageMedia", sender: message)
})
return cell
@@ -1201,7 +1430,10 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
case MessageMediaType.Image.rawValue:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightImageCellIdentifier, forIndexPath: indexPath) as! ChatRightImageCell
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio)
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: {
self.performSegueWithIdentifier("showMessageMedia", sender: message)
})
return cell
@@ -1209,14 +1441,21 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightAudioCellIdentifier, forIndexPath: indexPath) as! ChatRightAudioCell
let audioPlayedDuration = audioPlayedDurationOfMessage(message)
cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration)
cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { message in
self.playMessageAudioWithMessage(message)
})
return cell
case MessageMediaType.Video.rawValue:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightVideoCellIdentifier, forIndexPath: indexPath) as! ChatRightVideoCell
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio)
cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: {
self.performSegueWithIdentifier("showMessageMedia", sender: message)
})
return cell
@@ -1261,18 +1500,21 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if isKeyboardVisible {
if messageToolbar.state != .Default {
messageToolbar.state = .Default
} else {
}
/*
else {
let message = messages[displayedMessagesRange.location + indexPath.item]
switch message.mediaType {
case MessageMediaType.Image.rawValue:
performSegueWithIdentifier("presentMessageMedia", sender: message)
//performSegueWithIdentifier("presentMessageMedia", sender: message)
performSegueWithIdentifier("showMessageMedia", sender: message)
case MessageMediaType.Video.rawValue:
performSegueWithIdentifier("presentMessageMedia", sender: message)
//performSegueWithIdentifier("presentMessageMedia", sender: message)
performSegueWithIdentifier("showMessageMedia", sender: message)
case MessageMediaType.Audio.rawValue:
@@ -1302,7 +1544,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
}
}
if message == playingMessage {
if message.messageID == playingMessage.messageID {
return
}
}
@@ -1320,8 +1562,8 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi
}
}
*/
}
// MARK: UIScrollViewDelegate
@@ -17,6 +17,24 @@ class ConversationsViewController: UIViewController {
var realm: Realm!
var unreadMessagesToken: NotificationToken?
var haveUnreadMessages = false {
didSet {
if haveUnreadMessages != oldValue {
if haveUnreadMessages {
navigationController?.tabBarItem.image = UIImage(named: "icon_chat_unread")
navigationController?.tabBarItem.selectedImage = UIImage(named: "icon_chat_active_unread")
} else {
navigationController?.tabBarItem.image = UIImage(named: "icon_chat")
navigationController?.tabBarItem.selectedImage = UIImage(named: "icon_chat_active")
}
reloadConversationsTableView()
}
}
}
lazy var conversations: Results<Conversation> = {
return self.realm.objects(Conversation).sorted("updatedAt", ascending: false)
}()
@@ -32,6 +50,7 @@ class ConversationsViewController: UIViewController {
realm = Realm()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reloadConversationsTableView", name: YepNewMessagesReceivedNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "reloadConversationsTableView", name: ConversationViewController.Notification.MessageSent, object: nil)
YepUserDefaults.nickname.bindListener("ConversationsViewController.Nickname") { _ in
@@ -46,6 +65,10 @@ class ConversationsViewController: UIViewController {
conversationsTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
conversationsTableView.rowHeight = 80
unreadMessagesToken = realm.addNotificationBlock { notification, realm in
self.haveUnreadMessages = countOfUnreadMessagesInRealm(realm) > 0
}
}
override func viewDidAppear(animated: Bool) {
@@ -10,10 +10,12 @@ import UIKit
class CustomNavigationBarViewController: UIViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let navigationController = navigationController {
navigationController.navigationBar.backgroundColor = UIColor.clearColor()
navigationController.navigationBar.translucent = true
navigationController.navigationBar.shadowImage = UIImage()
@@ -30,24 +32,4 @@ class CustomNavigationBarViewController: UIViewController {
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if let navigationController = navigationController {
navigationController.navigationBar.backgroundColor = nil
navigationController.navigationBar.translucent = true
navigationController.navigationBar.shadowImage = nil
navigationController.navigationBar.barStyle = UIBarStyle.Default
navigationController.navigationBar.setBackgroundImage(nil, forBarMetrics: UIBarMetrics.Default)
let textAttributes = [
NSForegroundColorAttributeName: UIColor.yepTintColor(),
NSFontAttributeName: UIFont.navigationBarTitleFont()
]
navigationController.navigationBar.titleTextAttributes = textAttributes
navigationController.navigationBar.tintColor = nil
}
}
}
@@ -8,42 +8,94 @@
import UIKit
class DiscoverViewController: UIViewController {
class DiscoverViewController: BaseViewController {
@IBOutlet weak var discoverTableView: UITableView!
@IBOutlet weak var filterButtonItem: UIBarButtonItem!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
let cellIdentifier = "ContactsCell"
var discoveredUserSortStyle: DiscoveredUserSortStyle = .Default {
didSet {
filterButtonItem.title = discoveredUserSortStyle.name
activityIndicator.startAnimating()
discoverUsers(masterSkills: [], learningSkills: [], discoveredUserSortStyle: discoveredUserSortStyle, 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()
}
})
}
}
var discoveredUsers = [DiscoveredUser]() {
didSet {
updateDiscoverTableView()
}
}
var discoveredUsers = [DiscoveredUser]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = UIColor.whiteColor()
discoverTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
discoverTableView.rowHeight = 80
discoverTableView.dataSource = self
discoverTableView.delegate = self
discoverTableView.tableFooterView = UIView()
discoveredUserSortStyle = .Default
}
discoverUsers(masterSkills: [], learningSkills: [], discoveredUserSortStyle: .LastSignIn, failureHandler: { (reason, errorMessage) in
defaultFailureHandler(reason, errorMessage)
// MARK: Actions
}, completion: { discoveredUsers in
self.discoveredUsers = discoveredUsers
dispatch_async(dispatch_get_main_queue()) {
self.reloadDiscoverTableView()
}
})
@IBAction func showFilters(sender: UIBarButtonItem) {
moreAction()
}
func reloadDiscoverTableView() {
self.discoverTableView.reloadData()
func moreAction() {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
let nearbyAction: UIAlertAction = UIAlertAction(title: DiscoveredUserSortStyle.Distance.name, style: .Default) { action -> Void in
self.discoveredUserSortStyle = .Distance
}
alertController.addAction(nearbyAction)
let timeAction: UIAlertAction = UIAlertAction(title: DiscoveredUserSortStyle.LastSignIn.name, style: .Default) { action -> Void in
self.discoveredUserSortStyle = .LastSignIn
}
alertController.addAction(timeAction)
let defaultAction: UIAlertAction = UIAlertAction(title: DiscoveredUserSortStyle.Default.name, style: .Default) { action -> Void in
self.discoveredUserSortStyle = .Default
}
alertController.addAction(defaultAction)
let cancelAction: UIAlertAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel) { action -> Void in
}
alertController.addAction(cancelAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
func updateDiscoverTableView() {
//discoverTableView.reloadData()
discoverTableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: UITableViewRowAnimation.Automatic)
}
@@ -56,8 +108,12 @@ class DiscoverViewController: UIViewController {
let discoveredUser = discoveredUsers[indexPath.row]
let vc = segue.destinationViewController as! ProfileViewController
if discoveredUser.id != YepUserDefaults.userID.value {
vc.profileUser = ProfileUser.DiscoveredUserType(discoveredUser)
}
vc.profileUser = ProfileUser.DiscoveredUserType(discoveredUser)
vc.setBackButtonWithTitle()
vc.hidesBottomBarWhenPushed = true
}
@@ -87,8 +143,10 @@ extension DiscoverViewController: UITableViewDataSource, UITableViewDelegate {
}
}
cell.joinedDateLabel.text = discoveredUser.createdAt.timeAgo
cell.lastTimeSeenLabel.text = discoveredUser.lastSignInAt.timeAgo
cell.joinedDateLabel.text = discoveredUser.introduction
let distance = discoveredUser.distance.format(".1")
cell.lastTimeSeenLabel.text = "\(distance) km | \(discoveredUser.lastSignInAt.timeAgo)"
cell.nameLabel.text = discoveredUser.nickname
@@ -7,6 +7,7 @@
//
import UIKit
import RealmSwift
class EditProfileViewController: UIViewController {
@@ -41,6 +42,8 @@ class EditProfileViewController: UIViewController {
updateAvatar() {
}
mobileLabel.text = YepUserDefaults.mobile.value
editProfileTableView.registerNib(UINib(nibName: editProfileLessInfoCellIdentifier, bundle: nil), forCellReuseIdentifier: editProfileLessInfoCellIdentifier)
editProfileTableView.registerNib(UINib(nibName: editProfileMoreInfoCellIdentifier, bundle: nil), forCellReuseIdentifier: editProfileMoreInfoCellIdentifier)
editProfileTableView.registerNib(UINib(nibName: editProfileColoredTitleCellIdentifier, bundle: nil), forCellReuseIdentifier: editProfileColoredTitleCellIdentifier)
@@ -272,7 +275,34 @@ extension EditProfileViewController: UITableViewDataSource, UITableViewDelegate
default:
break
}
case Section.LogOut.rawValue:
YepAlert.confirmOrCancel(title: NSLocalizedString("Notice", comment: ""), message: NSLocalizedString("Do you want to logout?", comment: ""), confirmTitle: NSLocalizedString("Yes", comment: ""), cancelTitle: NSLocalizedString("Cancel", comment: ""), inViewController: self, withConfirmAction: { () -> Void in
YepUserDefaults.cleanAll()
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
appDelegate.startIntroStory()
}
// clean Realm
let realm = Realm()
realm.write {
realm.deleteAll()
}
// clean Message caches
NSFileManager.cleanMessageCaches()
// clean Avatar caches
NSFileManager.cleanAvatarCaches()
}, cancelAction: { () -> Void in
})
default:
break
}
@@ -67,7 +67,7 @@ class LoginByMobileViewController: UIViewController {
let mobile = mobileNumberTextField.text
let areaCode = areaCodeTextField.text
sendVerifyCode(ofMobile: mobile, withAreaCode: areaCode, failureHandler: { (reason, errorMessage) in
sendVerifyCodeOfMobile(mobile, withAreaCode: areaCode, useMethod: .SMS, failureHandler: { (reason, errorMessage) in
defaultFailureHandler(reason, errorMessage)
if let errorMessage = errorMessage {
@@ -84,7 +84,7 @@ class LoginVerifyMobileViewController: UIViewController {
func callMe() {
nextButton.setTitle(NSLocalizedString("Calling", comment: ""), forState: .Normal)
resendVoiceVerifyCode(ofMobile: mobile, withAreaCode: areaCode, failureHandler: { (reason, errorMessage) -> () in
sendVerifyCodeOfMobile(mobile, withAreaCode: areaCode, useMethod: .Call, failureHandler: { (reason, errorMessage) in
defaultFailureHandler(reason, errorMessage)
if let errorMessage = errorMessage {
@@ -21,9 +21,22 @@ class MessageMediaViewController: UIViewController {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: false)
}
override func viewDidLoad() {
super.viewDidLoad()
title = NSLocalizedString("Preview", comment: "")
self.view.backgroundColor = UIColor.blackColor()
self.mediaView.backgroundColor = UIColor.blackColor()
automaticallyAdjustsScrollViewInsets = false
if let message = message {
switch message.mediaType {
@@ -35,18 +48,12 @@ class MessageMediaViewController: UIViewController {
if
let imageFileURL = NSFileManager.yepMessageImageURLWithName(message.localAttachmentName),
let image = UIImage(contentsOfFile: imageFileURL.path!) {
mediaView.imageView.image = image
mediaView.image = image
mediaControlView.shareAction = {
let presentingViewController = self.presentingViewController
let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
self.dismissViewControllerAnimated(true, completion: { () -> Void in
let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
presentingViewController?.presentViewController(activityViewController, animated: true, completion: { () -> Void in
})
self.presentViewController(activityViewController, animated: true, completion: { () -> Void in
})
}
}
@@ -102,15 +109,9 @@ class MessageMediaViewController: UIViewController {
mediaControlView.shareAction = {
let presentingViewController = self.presentingViewController
let activityViewController = UIActivityViewController(activityItems: [videoFileURL], applicationActivities: nil)
self.dismissViewControllerAnimated(true, completion: { () -> Void in
let activityViewController = UIActivityViewController(activityItems: [videoFileURL], applicationActivities: nil)
presentingViewController?.presentViewController(activityViewController, animated: true, completion: { () -> Void in
})
self.presentViewController(activityViewController, animated: true, completion: { () -> Void in
})
}
}
@@ -135,7 +136,8 @@ class MessageMediaViewController: UIViewController {
}
}
dismissViewControllerAnimated(true, completion: nil)
// dismissViewControllerAnimated(true, completion: nil)
navigationController?.popViewControllerAnimated(true)
}
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
@@ -170,4 +172,8 @@ class MessageMediaViewController: UIViewController {
playerItem.seekToTime(kCMTimeZero)
}
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
@@ -0,0 +1,90 @@
//
// YepNavigationController.swift
// Yep
//
// Created by kevinzhow on 15/5/27.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
class YepNavigationController: UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
if respondsToSelector("interactivePopGestureRecognizer") {
interactivePopGestureRecognizer.delegate = self
delegate = self
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override init(rootViewController: UIViewController) {
super.init(rootViewController: rootViewController)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func pushViewController(viewController: UIViewController, animated: Bool) {
if respondsToSelector("interactivePopGestureRecognizer") && animated {
interactivePopGestureRecognizer.enabled = false
}
super.pushViewController(viewController, animated: animated)
}
override func popToRootViewControllerAnimated(animated: Bool) -> [AnyObject]? {
if respondsToSelector("interactivePopGestureRecognizer") && animated {
interactivePopGestureRecognizer.enabled = false
}
return super.popToRootViewControllerAnimated(animated)
}
override func popToViewController(viewController: UIViewController, animated: Bool) -> [AnyObject]? {
if respondsToSelector("interactivePopGestureRecognizer") && animated {
interactivePopGestureRecognizer.enabled = false
}
return super.popToViewController(viewController, animated: false)
}
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
if respondsToSelector("interactivePopGestureRecognizer") {
interactivePopGestureRecognizer.enabled = true
}
}
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == interactivePopGestureRecognizer
{
if self.viewControllers.count < 2 || self.visibleViewController == self.viewControllers[0] as! UIViewController
{
return false
}
}
return true
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
@@ -9,7 +9,7 @@
import UIKit
import WebViewJavascriptBridge
class OAuthViewController: UIViewController, UIWebViewDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate {
class OAuthViewController: BaseViewController, UIWebViewDelegate, NSURLConnectionDelegate, NSURLConnectionDataDelegate {
var socialAccount: SocialAccount!
var afterOAuthAction: ((socialAccount: SocialAccount) -> Void)?
@@ -17,6 +17,7 @@ class OAuthViewController: UIViewController, UIWebViewDelegate, NSURLConnectionD
@IBOutlet weak var webView: UIWebView!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var bridge: WebViewJavascriptBridge!
var authenticated = false
@@ -25,6 +26,11 @@ class OAuthViewController: UIViewController, UIWebViewDelegate, NSURLConnectionD
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
animatedOnNavigationBar = false
title = NSLocalizedString("OAuth", comment: "")
@@ -10,6 +10,9 @@ import UIKit
class ProfileLayout: UICollectionViewFlowLayout {
var scrollUpAction: ((progress: CGFloat) -> Void)?
let leftEdgeInset: CGFloat = YepConfig.Profile.leftEdgeInset
override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
@@ -22,8 +25,8 @@ class ProfileLayout: UICollectionViewFlowLayout {
if contentOffset.y < minY {
let deltaY = abs(contentOffset.y - minY)
for (index, attributes) in enumerate(layoutAttributes) {
if index == 0 {
for attributes in layoutAttributes {
if attributes.indexPath.section == ProfileViewController.ProfileSection.Header.rawValue {
var frame = attributes.frame
frame.size.height = max(minY, CGRectGetWidth(collectionView!.bounds) * profileAvatarAspectRatio + deltaY)
frame.origin.y = CGRectGetMinY(frame) - deltaY
@@ -32,11 +35,39 @@ class ProfileLayout: UICollectionViewFlowLayout {
break
}
}
} else {
let coverHeight = CGRectGetWidth(collectionView!.bounds) * profileAvatarAspectRatio
let coverHideHeight = coverHeight - 64
if contentOffset.y > coverHideHeight {
let deltaY = abs(contentOffset.y - minY)
for attributes in layoutAttributes {
if attributes.indexPath.section == ProfileViewController.ProfileSection.Header.rawValue {
var frame = attributes.frame
frame.origin.y = deltaY - coverHideHeight
attributes.frame = frame
attributes.zIndex = 1000
break
}
}
}
if coverHideHeight > contentOffset.y {
scrollUpAction?(progress: 1.0 - (coverHideHeight - contentOffset.y) / coverHideHeight)
} else {
scrollUpAction?(progress: 1.0)
}
}
// item centerY
var rowCollections = [CGFloat: [UICollectionViewLayoutAttributes]]()
for (index, attributes) in enumerate(layoutAttributes) {
for attributes in layoutAttributes {
let centerY = CGRectGetMidY(attributes.frame)
if let rowCollection = rowCollections[centerY] {
@@ -77,9 +108,9 @@ class ProfileLayout: UICollectionViewFlowLayout {
} else {
itemFrame.origin.x = CGRectGetMaxX(previousFrame) + minimumInteritemSpacing
}
}
attributes.frame = itemFrame
attributes.frame = itemFrame
}
previousFrame = itemFrame
}
@@ -78,18 +78,80 @@ enum SocialAccount: Int, Printable {
enum ProfileUser {
case DiscoveredUserType(DiscoveredUser)
case UserType(User)
func enabledSocialAccount(socialAccount: SocialAccount) -> Bool {
var accountEnabled = false
let providerName = socialAccount.description.lowercaseString
switch self {
case .DiscoveredUserType(let discoveredUser):
for provider in discoveredUser.socialAccountProviders {
if (provider.name == providerName) && provider.enabled {
accountEnabled = true
break
}
}
case .UserType(let user):
for provider in user.socialAccountProviders {
if (provider.name == providerName) && provider.enabled {
accountEnabled = true
break
}
}
}
return accountEnabled
}
}
class ProfileViewController: CustomNavigationBarViewController {
class ProfileViewController: UIViewController {
var isFromConversation = false
var profileUser: ProfileUser?
var profileUserIsMe = true {
didSet {
if !profileUserIsMe {
let moreBarButtonItem = UIBarButtonItem(image: UIImage(named: "icon_more"), style: UIBarButtonItemStyle.Plain, target: self, action: "moreAction")
customNavigationItem.rightBarButtonItem = moreBarButtonItem
if isFromConversation {
sayHiView.hidden = true
} else {
sayHiView.sayHiAction = {
self.sayHi()
}
profileCollectionView.contentInset.bottom = sayHiView.bounds.height
}
} else {
sayHiView.hidden = true
let settingsBarButtonItem = UIBarButtonItem(image: UIImage(named: "icon_settings"), style: UIBarButtonItemStyle.Plain, target: self, action: "showSettings")
customNavigationItem.rightBarButtonItem = settingsBarButtonItem
}
}
}
@IBOutlet weak var topShadowImageView: UIImageView!
@IBOutlet weak var profileCollectionView: UICollectionView!
@IBOutlet weak var sayHiView: UIView!
@IBOutlet weak var sayHiButton: UIButton!
@IBOutlet weak var sayHiView: SayHiView!
var customNavigationBar: UINavigationBar!
let skillCellIdentifier = "SkillCell"
let headerCellIdentifier = "ProfileHeaderCell"
@@ -123,18 +185,18 @@ class ProfileViewController: CustomNavigationBarViewController {
}
case .UserType(let user):
if !user.introduction.isEmpty {
introduction = user.introduction
}
}
} else {
introduction = YepUserDefaults.introduction.value
YepUserDefaults.introduction.bindListener("Profile.introductionText") { introduction in
if let introduction = introduction {
self.introductionText = introduction
self.updateProfileCollectionView()
if user.friendState == UserFriendState.Me.rawValue {
YepUserDefaults.introduction.bindListener("Profile.introductionText") { introduction in
if let introduction = introduction {
self.introductionText = introduction
self.updateProfileCollectionView()
}
}
}
}
}
@@ -142,11 +204,39 @@ class ProfileViewController: CustomNavigationBarViewController {
return introduction ?? NSLocalizedString("No Introduction yet.", comment: "")
}()
var masterSkills = [Skill]()
var learningSkills = [Skill]()
var masterSkills = [Skill]() {
didSet {
let realm = Realm()
typealias SocialWorkProviderInfo = [String: Bool]
var socialWorkProviderInfo = SocialWorkProviderInfo()
if let
myUserID = YepUserDefaults.userID.value,
me = userWithUserID(myUserID, inRealm: realm) {
realm.write {
me.masterSkills.removeAll()
let userSkills = userSkillsFromSkills(self.masterSkills, inRealm: realm)
me.masterSkills.extend(userSkills)
}
}
}
}
var learningSkills = [Skill]() {
didSet {
let realm = Realm()
if let
myUserID = YepUserDefaults.userID.value,
me = userWithUserID(myUserID, inRealm: realm) {
realm.write {
me.learningSkills.removeAll()
let userSkills = userSkillsFromSkills(self.learningSkills, inRealm: realm)
me.learningSkills.extend(userSkills)
}
}
}
}
//typealias SocialWorkProviderInfo = [String: Bool]
//var socialWorkProviderInfo = SocialWorkProviderInfo()
var dribbbleWork: DribbbleWork?
var instagramWork: InstagramWork?
@@ -163,11 +253,54 @@ class ProfileViewController: CustomNavigationBarViewController {
return ceil(rect.height) + 4
}
}
var customNavigationItem: UINavigationItem = UINavigationItem(title: "Details")
func setBackButtonWithTitle() {
let backBarButtonItem = UIBarButtonItem(image: UIImage(named: "icon_back"), style: UIBarButtonItemStyle.Plain, target: self, action: "popBack")
backBarButtonItem.tintColor = UIColor.whiteColor()
customNavigationItem.leftBarButtonItem = backBarButtonItem
}
func popBack() {
self.navigationController?.popViewControllerAnimated(true)
}
override func viewDidLoad() {
super.viewDidLoad()
if profileUser == nil {
if let
myUserID = YepUserDefaults.userID.value,
me = userWithUserID(myUserID, inRealm: Realm()) {
profileUser = ProfileUser.UserType(me)
profileUserIsMe = true
masterSkills = skillsFromUserSkillList(me.masterSkills)
learningSkills = skillsFromUserSkillList(me.learningSkills)
}
}
if let profileLayout = profileCollectionView.collectionViewLayout as? ProfileLayout {
profileLayout.scrollUpAction = { progress in
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
}
}
}
profileCollectionView.registerNib(UINib(nibName: skillCellIdentifier, bundle: nil), forCellWithReuseIdentifier: skillCellIdentifier)
profileCollectionView.registerNib(UINib(nibName: headerCellIdentifier, bundle: nil), forCellWithReuseIdentifier: headerCellIdentifier)
profileCollectionView.registerNib(UINib(nibName: footerCellIdentifier, bundle: nil), forCellWithReuseIdentifier: footerCellIdentifier)
@@ -181,6 +314,40 @@ class ProfileViewController: CustomNavigationBarViewController {
profileCollectionView.alwaysBounceVertical = true
automaticallyAdjustsScrollViewInsets = false
customNavigationBar = UINavigationBar(frame: CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 64.0))
customNavigationBar.alpha = 0
customNavigationBar.setItems([customNavigationItem], animated: false)
view.addSubview(customNavigationBar)
customNavigationBar.backgroundColor = UIColor.clearColor()
customNavigationBar.translucent = true
customNavigationBar.shadowImage = UIImage()
customNavigationBar.barStyle = UIBarStyle.BlackTranslucent
customNavigationBar.setBackgroundImage(UIImage(), forBarMetrics: UIBarMetrics.Default)
let textAttributes = [
NSForegroundColorAttributeName: UIColor.whiteColor(),
NSFontAttributeName: UIFont.navigationBarTitleFont()
]
customNavigationBar.titleTextAttributes = textAttributes
customNavigationBar.tintColor = UIColor.whiteColor()
//Make sure when pan edge screen collectionview not scroll
if let gestures = navigationController?.view.gestureRecognizers {
for recognizer in gestures
{
if recognizer.isKindOfClass(UIScreenEdgePanGestureRecognizer)
{
profileCollectionView.panGestureRecognizer.requireGestureRecognizerToFail(recognizer as! UIScreenEdgePanGestureRecognizer)
println("Require UIScreenEdgePanGestureRecognizer to failed")
break
}
}
}
if let tabBarController = tabBarController {
profileCollectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: CGRectGetHeight(tabBarController.tabBar.bounds), right: 0)
@@ -189,64 +356,51 @@ class ProfileViewController: CustomNavigationBarViewController {
if let profileUser = profileUser {
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
self.navigationItem.title = discoveredUser.nickname
customNavigationItem.title = discoveredUser.nickname
case .UserType(let user):
self.navigationItem.title = user.nickname
}
customNavigationItem.title = user.nickname
} else {
YepUserDefaults.nickname.bindAndFireListener("ProfileViewController.Title") { nickname in
self.navigationItem.title = nickname
if user.friendState == UserFriendState.Me.rawValue {
YepUserDefaults.nickname.bindListener("ProfileViewController.Title") { nickname in
self.customNavigationItem.title = nickname
}
}
}
}
if let profileUser = profileUser {
let moreBarButtonItem = UIBarButtonItem(image: UIImage(named: "icon_more"), style: UIBarButtonItemStyle.Plain, target: self, action: "moreAction")
navigationItem.rightBarButtonItem = moreBarButtonItem
sayHiButton.setTitle(NSLocalizedString("Say Hi", comment: ""), forState: .Normal)
sayHiButton.layer.cornerRadius = 5
sayHiButton.backgroundColor = UIColor.yepTintColor()
profileCollectionView.contentInset.bottom = sayHiView.bounds.height
switch profileUser {
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
userInfo(failureHandler: nil) { userInfo in
case .DiscoveredUserType(let discoveredUser):
profileUserIsMe = false
//println("userInfo: \(userInfo)")
case .UserType(let user):
if user.friendState == UserFriendState.Me.rawValue {
profileUserIsMe = true
if let introduction = userInfo["introduction"] as? String {
YepUserDefaults.introduction.value = introduction
}
if let skillsData = userInfo["master_skills"] as? [JSONDictionary] {
self.masterSkills = skillsFromSkillsData(skillsData)
}
if let skillsData = userInfo["learning_skills"] as? [JSONDictionary] {
self.learningSkills = skillsFromSkillsData(skillsData)
}
if let providerInfo = userInfo["providers"] as? SocialWorkProviderInfo {
self.socialWorkProviderInfo = providerInfo
}
dispatch_async(dispatch_get_main_queue()) {
self.profileCollectionView.reloadData()
}
} else {
profileUserIsMe = false
}
}
sayHiView.hidden = true
}
}
func showSettings() {
self.performSegueWithIdentifier("showSettings", sender: self)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: true)
customNavigationBar.alpha = 1.0
self.setNeedsStatusBarAppearanceUpdate()
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
@@ -275,7 +429,24 @@ class ProfileViewController: CustomNavigationBarViewController {
vc.afterOAuthAction = { socialAccount in
// provider enabled
let providerName = socialAccount.description.lowercaseString
self.socialWorkProviderInfo[providerName] = true
// self.socialWorkProviderInfo[providerName] = true
let realm = Realm()
if let
myUserID = YepUserDefaults.userID.value,
me = userWithUserID(myUserID, inRealm: realm) {
for socialAccountProvider in me.socialAccountProviders {
if socialAccountProvider.name == providerName {
realm.write {
socialAccountProvider.enabled = true
}
break
}
}
}
}
}
@@ -320,10 +491,12 @@ class ProfileViewController: CustomNavigationBarViewController {
// MARK: Actions
func updateProfileCollectionView() {
self.profileCollectionView.reloadData()
profileCollectionView.collectionViewLayout.invalidateLayout()
profileCollectionView.reloadData()
profileCollectionView.layoutIfNeeded()
}
@IBAction func sayHi(sender: UIButton) {
func sayHi() {
if let profileUser = profileUser {
@@ -338,8 +511,6 @@ class ProfileViewController: CustomNavigationBarViewController {
let newUser = User()
newUser.userID = discoveredUser.id
newUser.nickname = discoveredUser.nickname
newUser.avatarURLString = discoveredUser.avatarURLString
newUser.friendState = UserFriendState.Stranger.rawValue
@@ -350,19 +521,53 @@ class ProfileViewController: CustomNavigationBarViewController {
stranger = newUser
}
if let stranger = stranger {
if stranger.conversation == nil {
if let user = stranger {
realm.beginWrite()
//
user.lastSignInAt = discoveredUser.lastSignInAt
user.nickname = discoveredUser.nickname
if let introduction = discoveredUser.introduction {
user.introduction = introduction
}
user.avatarURLString = discoveredUser.avatarURLString
//
user.learningSkills.removeAll()
let learningUserSkills = userSkillsFromSkills(discoveredUser.learningSkills, inRealm: realm)
user.learningSkills.extend(learningUserSkills)
user.masterSkills.removeAll()
let masterUserSkills = userSkillsFromSkills(discoveredUser.masterSkills, inRealm: realm)
user.masterSkills.extend(masterUserSkills)
// Social Account Provider
user.socialAccountProviders.removeAll()
let socialAccountProviders = userSocialAccountProvidersFromSocialAccountProviders(discoveredUser.socialAccountProviders)
user.socialAccountProviders.extend(socialAccountProviders)
realm.commitWrite()
if user.conversation == nil {
let newConversation = Conversation()
newConversation.type = ConversationType.OneToOne.rawValue
newConversation.withFriend = stranger
newConversation.withFriend = user
realm.beginWrite()
realm.add(newConversation)
realm.commitWrite()
}
if let conversation = stranger.conversation {
if let conversation = user.conversation {
performSegueWithIdentifier("showConversation", sender: conversation)
NSNotificationCenter.defaultCenter().postNotificationName(YepNewMessagesReceivedNotification, object: nil)
@@ -370,21 +575,25 @@ class ProfileViewController: CustomNavigationBarViewController {
}
case .UserType(let user):
if user.conversation == nil {
let newConversation = Conversation()
newConversation.type = ConversationType.OneToOne.rawValue
newConversation.withFriend = user
if user.friendState != UserFriendState.Me.rawValue {
realm.beginWrite()
realm.add(newConversation)
realm.commitWrite()
}
if user.conversation == nil {
let newConversation = Conversation()
if let conversation = user.conversation {
performSegueWithIdentifier("showConversation", sender: conversation)
newConversation.type = ConversationType.OneToOne.rawValue
newConversation.withFriend = user
NSNotificationCenter.defaultCenter().postNotificationName(YepNewMessagesReceivedNotification, object: nil)
realm.beginWrite()
realm.add(newConversation)
realm.commitWrite()
}
if let conversation = user.conversation {
performSegueWithIdentifier("showConversation", sender: conversation)
NSNotificationCenter.defaultCenter().postNotificationName(YepNewMessagesReceivedNotification, object: nil)
}
}
}
}
@@ -420,7 +629,7 @@ class ProfileViewController: CustomNavigationBarViewController {
// MARK: UICollectionView
extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDelegate {
extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDelegate, UIGestureRecognizerDelegate {
enum ProfileSection: Int {
case Header = 0
@@ -430,7 +639,6 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
case SeparationLine
case SocialAccount
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 6
@@ -451,11 +659,10 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
case .UserType(let user):
return Int(user.masterSkills.count)
}
} else {
return masterSkills.count
}
return 0
case ProfileSection.Learning.rawValue:
if let profileUser = profileUser {
@@ -465,11 +672,10 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
case .UserType(let user):
return Int(user.learningSkills.count)
}
} else {
return learningSkills.count
}
return 0
case ProfileSection.Footer.rawValue:
return 1
@@ -498,9 +704,6 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
case .UserType(let user):
cell.configureWithUser(user)
}
} else {
cell.configureWithMyInfo()
}
return cell
@@ -517,10 +720,6 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
let userSkill = user.masterSkills[indexPath.item]
cell.skillLabel.text = userSkill.localName
}
} else {
let skill = masterSkills[indexPath.item]
cell.skillLabel.text = skill.localName
}
return cell
@@ -537,13 +736,8 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
let userSkill = user.learningSkills[indexPath.item]
cell.skillLabel.text = userSkill.localName
}
} else {
let skill = learningSkills[indexPath.item]
cell.skillLabel.text = skill.localName
}
return cell
case ProfileSection.Footer.rawValue:
@@ -565,7 +759,7 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
if socialAccount == .Github {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(socialAccountGithubCellIdentifier, forIndexPath: indexPath) as! ProfileSocialAccountGithubCell
cell.configureWithProfileUser(profileUser, orSocialWorkProviderInfo: socialWorkProviderInfo, socialAccount: socialAccount, githubWork: githubWork, completion: { githubWork in
cell.configureWithProfileUser(profileUser, socialAccount: socialAccount, githubWork: githubWork, completion: { githubWork in
self.githubWork = githubWork
})
@@ -593,10 +787,12 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
break
}
cell.configureWithProfileUser(profileUser, orSocialWorkProviderInfo: socialWorkProviderInfo, socialAccount: socialAccount, socialWork: socialWork, completion: { socialWork in
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
}
@@ -623,8 +819,6 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
let header = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: sectionHeaderIdentifier, forIndexPath: indexPath) as! ProfileSectionHeaderReusableView
var needEnabledTapAction = (profileUser == nil)
switch indexPath.section {
case ProfileSection.Master.rawValue:
@@ -635,11 +829,9 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
default:
header.titleLabel.text = ""
needEnabledTapAction = false
}
if needEnabledTapAction {
if profileUserIsMe {
header.tapAction = {
let storyboard = UIStoryboard(name: "Intro", bundle: nil)
@@ -702,56 +894,80 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
switch indexPath.section {
case ProfileSection.Header.rawValue:
return CGSizeMake(collectionViewWidth, collectionViewWidth * profileAvatarAspectRatio)
return CGSize(width: collectionViewWidth, height: collectionViewWidth * profileAvatarAspectRatio)
case ProfileSection.Master.rawValue:
var skillLocalName = ""
if let profileUser = profileUser {
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
skillLocalName = discoveredUser.masterSkills[indexPath.item].localName
case .UserType(let user):
let userSkill = user.masterSkills[indexPath.item]
skillLocalName = userSkill.localName
}
} else {
skillLocalName = masterSkills[indexPath.item].localName
}
let rect = skillLocalName.boundingRectWithSize(CGSize(width: CGFloat(FLT_MAX), height: SkillCell.height), options: .UsesLineFragmentOrigin | .UsesFontLeading, attributes: skillTextAttributes, context: nil)
return CGSizeMake(rect.width + 24, SkillCell.height)
return CGSize(width: rect.width + 24, height: SkillCell.height)
case ProfileSection.Learning.rawValue:
var skillLocalName = ""
if let profileUser = profileUser {
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
skillLocalName = discoveredUser.learningSkills[indexPath.item].localName
case .UserType(let user):
let userSkill = user.learningSkills[indexPath.item]
skillLocalName = userSkill.localName
}
} else {
skillLocalName = learningSkills[indexPath.item].localName
}
let rect = skillLocalName.boundingRectWithSize(CGSize(width: CGFloat(FLT_MAX), height: SkillCell.height), options: .UsesLineFragmentOrigin | .UsesFontLeading, attributes: skillTextAttributes, context: nil)
return CGSizeMake(rect.width + 24, SkillCell.height)
return CGSize(width: rect.width + 24, height: SkillCell.height)
case ProfileSection.Footer.rawValue:
return CGSizeMake(collectionViewWidth, footerCellHeight)
return CGSize(width: collectionViewWidth, height: footerCellHeight)
case ProfileSection.SeparationLine.rawValue:
return CGSizeMake(collectionViewWidth, 1)
var enabled = true
if let profileUser = profileUser {
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
enabled = discoveredUser.socialAccountProviders.filter({ socialAccountProvider in
socialAccountProvider.enabled
}).count > 0
case .UserType(let user):
if user.friendState != UserFriendState.Me.rawValue {
enabled = user.socialAccountProviders.filter("enabled = true").count > 0
}
}
}
return enabled ? CGSize(width: collectionViewWidth, height: 1) : CGSizeZero
case ProfileSection.SocialAccount.rawValue:
return CGSizeMake(collectionViewWidth, 40)
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
default:
return CGSizeZero
@@ -764,12 +980,12 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
return CGSizeMake(collectionViewWidth, 40)
} else {
return CGSizeMake(collectionViewWidth, 0)
return CGSizeZero
}
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSizeMake(collectionViewWidth, 0)
return CGSizeZero
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
@@ -783,45 +999,19 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel
if let socialAccount = SocialAccount(rawValue: indexPath.item) {
let providerName = socialAccount.description.lowercaseString
if let profileUser = profileUser {
switch profileUser {
case .DiscoveredUserType(let discoveredUser):
for provider in discoveredUser.socialAccountProviders {
if (provider.name == providerName) && provider.enabled {
performSegueWithIdentifier("showSocialWork\(socialAccount)", sender: indexPath.item)
if profileUser.enabledSocialAccount(socialAccount) {
performSegueWithIdentifier("showSocialWork\(socialAccount)", sender: indexPath.item)
break
}
}
case .UserType(let user):
for provider in user.socialAccountProviders {
if (provider.name == providerName) && provider.enabled {
performSegueWithIdentifier("showSocialWork\(socialAccount)", sender: indexPath.item)
break
}
} else {
if profileUserIsMe {
performSegueWithIdentifier("presentOAuth", sender: indexPath.item)
}
}
} else {
if let enabled = socialWorkProviderInfo[providerName] {
if enabled {
performSegueWithIdentifier("showSocialWork\(socialAccount)", sender: indexPath.item)
return
}
}
performSegueWithIdentifier("presentOAuth", sender: indexPath.item)
}
}
}
}
}
@@ -8,7 +8,7 @@
import UIKit
class RegisterPickSkillsViewController: UIViewController {
class RegisterPickSkillsViewController: BaseViewController {
var isRegister = true
var afterChangeSkillsAction: ((masterSkills: [Skill], learningSkills: [Skill]) -> Void)?
@@ -35,7 +35,6 @@ class RegisterPickSkillsViewController: UIViewController {
var skillCategories: [SkillCategory]?
lazy var selectSkillsTransitionManager = RegisterPickSkillsSelectSkillsTransitionManager()
override func viewDidLoad() {
@@ -67,6 +66,10 @@ class RegisterPickSkillsViewController: UIViewController {
// MARK: Actions
func updateSkillsCollectionView() {
skillsCollectionView.reloadData()
}
@IBAction func saveSkills(sender: AnyObject) {
let addSkillsGroup = dispatch_group_create()
@@ -194,7 +197,7 @@ class RegisterPickSkillsViewController: UIViewController {
break
}
self.skillsCollectionView.reloadData()
self.updateSkillsCollectionView()
return success
}
@@ -110,11 +110,11 @@ class RegisterSelectSkillsViewController: UIViewController {
allSkillCategories(failureHandler: { (reason, errorMessage) -> Void in
defaultFailureHandler(reason, errorMessage)
}, completion: { skillCategories -> Void in
}, completion: { skillCategories in
self.skillCategories = skillCategories
dispatch_async(dispatch_get_main_queue()) {
self.skillsCollectionView.reloadData()
self.updateSkillsCollectionView()
}
})
}
@@ -126,6 +126,14 @@ class RegisterSelectSkillsViewController: UIViewController {
skillsCollectionViewBottomConstrain.constant = -CGRectGetHeight(skillsCollectionView.bounds)
}
// MARK: Actions
func updateSkillsCollectionView() {
skillsCollectionView.collectionViewLayout.invalidateLayout()
skillsCollectionView.reloadData()
skillsCollectionView.layoutIfNeeded()
}
func dismiss() {
presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
@@ -84,7 +84,7 @@ class RegisterVerifyMobileViewController: UIViewController {
func callMe() {
nextButton.setTitle(NSLocalizedString("Calling", comment: ""), forState: .Normal)
resendVoiceVerifyCode(ofMobile: mobile, withAreaCode: areaCode, failureHandler: { (reason, errorMessage) -> () in
sendVerifyCodeOfMobile(mobile, withAreaCode: areaCode, useMethod: .Call, failureHandler: { (reason, errorMessage) in
defaultFailureHandler(reason, errorMessage)
if let errorMessage = errorMessage {
@@ -8,7 +8,7 @@
import UIKit
class SearchUsersViewController: UIViewController {
class SearchUsersViewController: BaseViewController {
@IBOutlet weak var searchedUsersTableView: UITableView!
@@ -0,0 +1,107 @@
//
// SearchedUsersViewController.swift
// Yep
//
// Created by NIX on 15/5/22.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
class SearchedUsersViewController: BaseViewController {
var mobile = "18602354812"
@IBOutlet weak var searchedUsersTableView: UITableView!
var searchedUsers = [DiscoveredUser]() {
didSet {
updateSearchedUsersTableView()
}
}
let cellIdentifier = "ContactsCell"
override func viewDidLoad() {
super.viewDidLoad()
title = NSLocalizedString("Searched Users", comment: "")
searchedUsersTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
searchedUsersTableView.rowHeight = 80
searchUsersByQ(mobile, failureHandler: { (reason, errorMessage) in
defaultFailureHandler(reason, errorMessage)
}, completion: { users in
dispatch_async(dispatch_get_main_queue()) {
self.searchedUsers = users
}
})
}
// MARK: Actions
func updateSearchedUsersTableView() {
searchedUsersTableView.reloadData()
}
// MARK: Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showProfile" {
if let indexPath = sender as? NSIndexPath {
let discoveredUser = searchedUsers[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 SearchedUsersViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchedUsers.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! ContactsCell
let discoveredUser = searchedUsers[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)
}
}
@@ -8,7 +8,7 @@
import UIKit
class SettingsViewController: UIViewController {
class SettingsViewController: BaseViewController {
@IBOutlet weak var settingsTableView: UITableView!
@@ -32,6 +32,8 @@ class SettingsViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
animatedOnNavigationBar = false
title = NSLocalizedString("Settings", comment: "")
@@ -26,18 +26,18 @@ class SkillHomeViewController: CustomNavigationBarViewController {
let cellIdentifier = "ContactsCell"
lazy var masterTableView: UITableView = {
lazy var masterTableView: YepChildScrollView = {
var tempTableView = UITableView(frame: CGRectZero)
var tempTableView = YepChildScrollView(frame: CGRectZero)
return tempTableView;
}()
lazy var learningtTableView: UITableView = {
lazy var learningtTableView: YepChildScrollView = {
var tempTableView = UITableView(frame: CGRectZero)
var tempTableView = YepChildScrollView(frame: CGRectZero)
return tempTableView;
@@ -50,6 +50,11 @@ class SkillHomeViewController: CustomNavigationBarViewController {
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
var isFirstAppear = true
var state: SkillHomeState = .Master {
@@ -71,7 +76,7 @@ class SkillHomeViewController: CustomNavigationBarViewController {
}
}
@IBOutlet weak var skillHomeScrollView: UIScrollView!
@IBOutlet weak var skillHomeScrollView: YepScrollView!
@IBOutlet weak var headerView: SkillHomeHeaderView!
@@ -80,6 +85,7 @@ class SkillHomeViewController: CustomNavigationBarViewController {
var discoveredMasterUsers = [DiscoveredUser]()
var discoveredLearningUsers = [DiscoveredUser]()
override func viewDidLoad() {
super.viewDidLoad()
@@ -90,7 +96,6 @@ class SkillHomeViewController: CustomNavigationBarViewController {
masterTableView.delegate = self
masterTableView.tag = SkillHomeState.Master.hashValue
learningtTableView.registerNib(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
learningtTableView.rowHeight = 80
learningtTableView.dataSource = self
@@ -106,13 +111,30 @@ class SkillHomeViewController: CustomNavigationBarViewController {
headerView.masterButton.addTarget(self, action: "changeToMaster", forControlEvents: UIControlEvents.TouchUpInside)
headerView.learningButton.addTarget(self, action: "changeToLearning", forControlEvents: UIControlEvents.TouchUpInside)
automaticallyAdjustsScrollViewInsets = false
skillHomeScrollView.addSubview(masterTableView)
skillHomeScrollView.addSubview(learningtTableView)
skillHomeScrollView.pagingEnabled = true
skillHomeScrollView.delegate = self
skillHomeScrollView.bounces = false
if let gestures = navigationController?.view.gestureRecognizers {
for recognizer in gestures
{
if recognizer.isKindOfClass(UIScreenEdgePanGestureRecognizer)
{
skillHomeScrollView.panGestureRecognizer.requireGestureRecognizerToFail(recognizer as! UIScreenEdgePanGestureRecognizer)
println("Require UIScreenEdgePanGestureRecognizer to failed")
break
}
}
}
customTitleView()
// Do any additional setup after loading the view.
}
@@ -183,7 +205,9 @@ class SkillHomeViewController: CustomNavigationBarViewController {
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if scrollView.contentOffset.x >= scrollView.contentSize.width / 2 {
println("Did end decelerating \(skillHomeScrollView.contentOffset.x)")
if skillHomeScrollView.contentOffset.x + 10 >= skillHomeScrollView.contentSize.width / 2.0 {
state = .Learning
@@ -238,9 +262,13 @@ class SkillHomeViewController: CustomNavigationBarViewController {
let vc = segue.destinationViewController as! ProfileViewController
vc.profileUser = ProfileUser.DiscoveredUserType(discoveredUser)
if discoveredUser.id != YepUserDefaults.userID.value {
vc.profileUser = ProfileUser.DiscoveredUserType(discoveredUser)
}
vc.hidesBottomBarWhenPushed = true
vc.setBackButtonWithTitle()
}
}
}
@@ -277,8 +305,10 @@ extension SkillHomeViewController: UITableViewDelegate, UITableViewDataSource{
}
}
cell.joinedDateLabel.text = discoveredUser.createdAt.timeAgo
cell.lastTimeSeenLabel.text = discoveredUser.lastSignInAt.timeAgo
cell.joinedDateLabel.text = discoveredUser.introduction
let distance = discoveredUser.distance.format(".1")
cell.lastTimeSeenLabel.text = "\(distance) km | \(discoveredUser.lastSignInAt.timeAgo)"
cell.nameLabel.text = discoveredUser.nickname
@@ -9,7 +9,7 @@
import UIKit
import Kingfisher
class SocialWorkDribbbleViewController: UIViewController {
class SocialWorkDribbbleViewController: BaseViewController {
var socialAccount: SocialAccount?
var profileUser: ProfileUser?
@@ -36,10 +36,13 @@ class SocialWorkDribbbleViewController: UIViewController {
updateDribbbleCollectionView()
}
}
override func viewDidLoad() {
super.viewDidLoad()
animatedOnNavigationBar = false
if let socialAccount = socialAccount {
let accountImageView = UIImageView(image: UIImage(named: socialAccount.iconName)!)
accountImageView.tintColor = socialAccount.tintColor
@@ -71,9 +74,6 @@ class SocialWorkDribbbleViewController: UIViewController {
case .UserType(let user):
userID = user.userID
}
} else {
userID = YepUserDefaults.userID.value
}
if let userID = userID {
@@ -8,7 +8,7 @@
import UIKit
class SocialWorkGithubViewController: UIViewController {
class SocialWorkGithubViewController: BaseViewController {
var socialAccount: SocialAccount?
var profileUser: ProfileUser?
@@ -65,7 +65,8 @@ class SocialWorkGithubViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.whiteColor()
animatedOnNavigationBar = false
if let socialAccount = socialAccount {
let accountImageView = UIImageView(image: UIImage(named: socialAccount.iconName)!)
@@ -100,9 +101,6 @@ class SocialWorkGithubViewController: UIViewController {
case .UserType(let user):
userID = user.userID
}
} else {
userID = YepUserDefaults.userID.value
}
if let userID = userID {
@@ -8,7 +8,7 @@
import UIKit
class SocialWorkInstagramViewController: UIViewController {
class SocialWorkInstagramViewController: BaseViewController {
var socialAccount: SocialAccount?
var profileUser: ProfileUser?
@@ -38,6 +38,8 @@ class SocialWorkInstagramViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
animatedOnNavigationBar = false
if let socialAccount = socialAccount {
let accountImageView = UIImageView(image: UIImage(named: socialAccount.iconName)!)
@@ -69,9 +71,6 @@ class SocialWorkInstagramViewController: UIViewController {
case .UserType(let user):
userID = user.userID
}
} else {
userID = YepUserDefaults.userID.value
}
if let userID = userID {
@@ -12,16 +12,16 @@ class YepTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
// UITabBarItem image title
if let items = tabBar.items as? [UITabBarItem] {
for item in items {
item.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)
item.title = nil
}
}
// if let items = tabBar.items as? [UITabBarItem] {
// for item in items {
// item.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)
// item.title = nil
// }
// }
}
}
@@ -0,0 +1,30 @@
//
// AddFriendMoreCell.swift
// Yep
//
// Created by NIX on 15/5/19.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
class AddFriendMoreCell: UITableViewCell {
@IBOutlet weak var annotationLabel: UILabel!
@IBOutlet weak var accessoryImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
accessoryImageView.tintColor = UIColor.lightGrayColor()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="AddFriendMoreCell" id="KGk-i7-Jjw" customClass="AddFriendMoreCell" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="More" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rFJ-sX-tIW" userLabel="Annotation Label">
<rect key="frame" x="20" y="11" width="40" height="22"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="18"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_accessory" translatesAutoresizingMaskIntoConstraints="NO" id="kCv-aC-1z1" userLabel="Accessory Image View">
<rect key="frame" x="289" y="12" width="11" height="20"/>
</imageView>
</subviews>
<constraints>
<constraint firstItem="kCv-aC-1z1" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="rFJ-sX-tIW" secondAttribute="trailing" constant="10" id="0De-1O-4MH"/>
<constraint firstItem="rFJ-sX-tIW" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="20" id="A1H-Lw-FVI"/>
<constraint firstAttribute="centerY" secondItem="rFJ-sX-tIW" secondAttribute="centerY" id="CCq-gC-j1w"/>
<constraint firstAttribute="centerY" secondItem="kCv-aC-1z1" secondAttribute="centerY" id="LKT-hk-b97"/>
<constraint firstAttribute="trailing" secondItem="kCv-aC-1z1" secondAttribute="trailing" constant="20" id="bDU-de-Kdw"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="accessoryImageView" destination="kCv-aC-1z1" id="v40-9S-4Ce"/>
<outlet property="annotationLabel" destination="rFJ-sX-tIW" id="BkL-Ji-WWZ"/>
</connections>
</tableViewCell>
</objects>
<resources>
<image name="icon_accessory" width="11" height="20"/>
</resources>
</document>
@@ -0,0 +1,26 @@
//
// AddFriendSearchCell.swift
// Yep
//
// Created by NIX on 15/5/19.
// Copyright (c) 2015 Catch Inc. All rights reserved.
//
import UIKit
class AddFriendSearchCell: UITableViewCell {
@IBOutlet weak var searchTextField: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="AddFriendSearchCell" id="KGk-i7-Jjw" customClass="AddFriendSearchCell" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Search User" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="KnA-fN-H2T">
<rect key="frame" x="15" y="7" width="290" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="KTm-B0-qLG"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="centerY" secondItem="KnA-fN-H2T" secondAttribute="centerY" id="3KS-vH-9A8"/>
<constraint firstAttribute="trailing" secondItem="KnA-fN-H2T" secondAttribute="trailing" constant="15" id="luy-4A-RBW"/>
<constraint firstItem="KnA-fN-H2T" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="15" id="x5e-s3-lVB"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="searchTextField" destination="KnA-fN-H2T" id="vBa-kJ-dN3"/>
</connections>
</tableViewCell>
</objects>
</document>
@@ -10,7 +10,7 @@ import UIKit
class ChatLeftAudioCell: UICollectionViewCell {
var message: Message!
var message: Message?
var audioPlayedDuration: Double = 0 {
willSet {
@@ -43,6 +43,9 @@ class ChatLeftAudioCell: UICollectionViewCell {
@IBOutlet weak var playButton: UIButton!
typealias AudioBubbleTapAction = (message: Message?) -> Void
var audioBubbleTapAction: AudioBubbleTapAction?
override func awakeFromNib() {
super.awakeFromNib()
@@ -56,12 +59,22 @@ class ChatLeftAudioCell: UICollectionViewCell {
playButton.userInteractionEnabled = false
playButton.tintColor = UIColor.darkGrayColor()
bubbleImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tapMediaView")
bubbleImageView.addGestureRecognizer(tap)
}
func configureWithMessage(message: Message, audioPlayedDuration: Double) {
func tapMediaView() {
audioBubbleTapAction?(message: message)
}
func configureWithMessage(message: Message, audioPlayedDuration: Double, audioBubbleTapAction: AudioBubbleTapAction?) {
self.message = message
self.audioBubbleTapAction = audioBubbleTapAction
self.audioPlayedDuration = audioPlayedDuration
if let sender = message.fromFriend {
@@ -76,42 +89,46 @@ class ChatLeftAudioCell: UICollectionViewCell {
}
func updateAudioInfoViews() {
if !message.metaData.isEmpty {
if let message = message {
if let data = message.metaData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
if let metaDataDict = decodeJSON(data) {
if !message.metaData.isEmpty {
if let audioSamples = metaDataDict["audio_samples"] as? [CGFloat] {
sampleViewWidthConstraint.constant = CGFloat(audioSamples.count) * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap()) - YepConfig.audioSampleGap() // gap
sampleViewWidthConstraint.constant = max(YepConfig.minMessageSampleViewWidth, sampleViewWidthConstraint.constant)
sampleView.samples = audioSamples
if let data = message.metaData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
if let metaDataDict = decodeJSON(data) {
if let audioDuration = metaDataDict["audio_duration"] as? Double {
audioDurationLabel.text = NSString(format: "%.1f\"", audioDuration) as String
if let audioSamples = metaDataDict["audio_samples"] as? [CGFloat] {
sampleViewWidthConstraint.constant = CGFloat(audioSamples.count) * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap()) - YepConfig.audioSampleGap() // gap
sampleView.progress = CGFloat(audioPlayedDuration / audioDuration)
sampleViewWidthConstraint.constant = max(YepConfig.minMessageSampleViewWidth, sampleViewWidthConstraint.constant)
} else {
sampleView.progress = 0
sampleView.samples = audioSamples
if let audioDuration = metaDataDict["audio_duration"] as? Double {
audioDurationLabel.text = NSString(format: "%.1f\"", audioDuration) as String
sampleView.progress = CGFloat(audioPlayedDuration / audioDuration)
} else {
sampleView.progress = 0
}
}
}
} else {
sampleViewWidthConstraint.constant = 15 * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap())
audioDurationLabel.text = ""
}
} else {
sampleViewWidthConstraint.constant = 15 * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap())
audioDurationLabel.text = ""
}
}
if let audioPlayer = YepAudioService.sharedManager.audioPlayer {
if audioPlayer.playing {
if let playingMessage = YepAudioService.sharedManager.playingMessage {
if message == playingMessage {
playing = true
return
if let audioPlayer = YepAudioService.sharedManager.audioPlayer {
if audioPlayer.playing {
if let playingMessage = YepAudioService.sharedManager.playingMessage {
if message.messageID == playingMessage.messageID {
playing = true
return
}
}
}
}
@@ -16,16 +16,30 @@ class ChatLeftImageCell: UICollectionViewCell {
@IBOutlet weak var messageImageView: UIImageView!
@IBOutlet weak var messageImageViewWidthConstrint: NSLayoutConstraint!
typealias MediaTapAction = () -> Void
var mediaTapAction: MediaTapAction?
override func awakeFromNib() {
super.awakeFromNib()
avatarImageViewWidthConstraint.constant = YepConfig.chatCellAvatarSize()
messageImageView.tintColor = UIColor.leftBubbleTintColor()
messageImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tapMediaView")
messageImageView.addGestureRecognizer(tap)
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat) {
func tapMediaView() {
mediaTapAction?()
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat, mediaTapAction: MediaTapAction?) {
self.mediaTapAction = mediaTapAction
if let sender = message.fromFriend {
AvatarCache.sharedInstance.roundAvatarOfUser(sender, withRadius: YepConfig.chatCellAvatarSize() * 0.5) { roundImage in
dispatch_async(dispatch_get_main_queue()) {
@@ -18,15 +18,29 @@ class ChatLeftVideoCell: UICollectionViewCell {
@IBOutlet weak var playImageView: UIImageView!
typealias MediaTapAction = () -> Void
var mediaTapAction: MediaTapAction?
override func awakeFromNib() {
super.awakeFromNib()
avatarImageViewWidthConstraint.constant = YepConfig.chatCellAvatarSize()
thumbnailImageView.tintColor = UIColor.leftBubbleTintColor()
thumbnailImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tapMediaView")
thumbnailImageView.addGestureRecognizer(tap)
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat) {
func tapMediaView() {
mediaTapAction?()
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat, mediaTapAction: MediaTapAction?) {
self.mediaTapAction = mediaTapAction
if let sender = message.fromFriend {
AvatarCache.sharedInstance.roundAvatarOfUser(sender, withRadius: YepConfig.chatCellAvatarSize() * 0.5) { roundImage in
dispatch_async(dispatch_get_main_queue()) {
@@ -10,7 +10,7 @@ import UIKit
class ChatRightAudioCell: UICollectionViewCell {
var message: Message!
var message: Message?
var audioPlayedDuration: Double = 0 {
willSet {
@@ -42,6 +42,9 @@ class ChatRightAudioCell: UICollectionViewCell {
@IBOutlet weak var playButton: UIButton!
typealias AudioBubbleTapAction = (message: Message?) -> Void
var audioBubbleTapAction: AudioBubbleTapAction?
override func awakeFromNib() {
super.awakeFromNib()
@@ -54,12 +57,22 @@ class ChatRightAudioCell: UICollectionViewCell {
audioDurationLabel.textColor = UIColor.whiteColor()
playButton.userInteractionEnabled = false
bubbleImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tapMediaView")
bubbleImageView.addGestureRecognizer(tap)
}
func configureWithMessage(message: Message, audioPlayedDuration: Double) {
func tapMediaView() {
audioBubbleTapAction?(message: message)
}
func configureWithMessage(message: Message, audioPlayedDuration: Double, audioBubbleTapAction: AudioBubbleTapAction?) {
self.message = message
self.audioBubbleTapAction = audioBubbleTapAction
self.audioPlayedDuration = audioPlayedDuration
if let sender = message.fromFriend {
@@ -74,47 +87,51 @@ class ChatRightAudioCell: UICollectionViewCell {
}
func updateAudioInfoViews() {
if !message.metaData.isEmpty {
if let data = message.metaData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
if let metaDataDict = decodeJSON(data) {
if let message = message {
if let audioSamples = metaDataDict["audio_samples"] as? [CGFloat] {
sampleViewWidthConstraint.constant = CGFloat(audioSamples.count) * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap()) - YepConfig.audioSampleGap() // gap
sampleViewWidthConstraint.constant = max(YepConfig.minMessageSampleViewWidth, sampleViewWidthConstraint.constant)
sampleView.samples = audioSamples
if !message.metaData.isEmpty {
if let audioDuration = metaDataDict["audio_duration"] as? Double {
audioDurationLabel.text = NSString(format: "%.1f\"", audioDuration) as String
if let data = message.metaData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
if let metaDataDict = decodeJSON(data) {
sampleView.progress = CGFloat(audioPlayedDuration / audioDuration)
if let audioSamples = metaDataDict["audio_samples"] as? [CGFloat] {
sampleViewWidthConstraint.constant = CGFloat(audioSamples.count) * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap()) - YepConfig.audioSampleGap() // gap
} else {
sampleView.progress = 0
sampleViewWidthConstraint.constant = max(YepConfig.minMessageSampleViewWidth, sampleViewWidthConstraint.constant)
sampleView.samples = audioSamples
if let audioDuration = metaDataDict["audio_duration"] as? Double {
audioDurationLabel.text = NSString(format: "%.1f\"", audioDuration) as String
sampleView.progress = CGFloat(audioPlayedDuration / audioDuration)
} else {
sampleView.progress = 0
}
}
}
} else {
sampleViewWidthConstraint.constant = 15 * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap())
audioDurationLabel.text = ""
}
}
if let audioPlayer = YepAudioService.sharedManager.audioPlayer {
if audioPlayer.playing {
if let playingMessage = YepAudioService.sharedManager.playingMessage {
if message.messageID == playingMessage.messageID {
playing = true
return
}
}
}
} else {
sampleViewWidthConstraint.constant = 15 * (YepConfig.audioSampleWidth() + YepConfig.audioSampleGap())
audioDurationLabel.text = ""
}
}
if let audioPlayer = YepAudioService.sharedManager.audioPlayer {
if audioPlayer.playing {
if let playingMessage = YepAudioService.sharedManager.playingMessage {
if message == playingMessage {
playing = true
return
}
}
}
}
playing = false
}
}
@@ -16,6 +16,10 @@ class ChatRightImageCell: UICollectionViewCell {
@IBOutlet weak var messageImageView: UIImageView!
@IBOutlet weak var messageImageViewWidthConstrint: NSLayoutConstraint!
typealias MediaTapAction = () -> Void
var mediaTapAction: MediaTapAction?
override func awakeFromNib() {
super.awakeFromNib()
@@ -23,9 +27,20 @@ class ChatRightImageCell: UICollectionViewCell {
avatarImageViewWidthConstraint.constant = YepConfig.chatCellAvatarSize()
messageImageView.tintColor = UIColor.rightBubbleTintColor()
messageImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tapMediaView")
messageImageView.addGestureRecognizer(tap)
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat) {
func tapMediaView() {
mediaTapAction?()
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat, mediaTapAction: MediaTapAction?) {
self.mediaTapAction = mediaTapAction
if let sender = message.fromFriend {
AvatarCache.sharedInstance.roundAvatarOfUser(sender, withRadius: YepConfig.chatCellAvatarSize() * 0.5) { roundImage in
dispatch_async(dispatch_get_main_queue()) {
@@ -17,6 +17,9 @@ class ChatRightVideoCell: UICollectionViewCell {
@IBOutlet weak var thumbnailImageViewWidthConstraint: NSLayoutConstraint!
@IBOutlet weak var playImageView: UIImageView!
typealias MediaTapAction = () -> Void
var mediaTapAction: MediaTapAction?
override func awakeFromNib() {
super.awakeFromNib()
@@ -24,9 +27,20 @@ class ChatRightVideoCell: UICollectionViewCell {
avatarImageViewWidthConstraint.constant = YepConfig.chatCellAvatarSize()
thumbnailImageView.tintColor = UIColor.rightBubbleTintColor()
thumbnailImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tapMediaView")
thumbnailImageView.addGestureRecognizer(tap)
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat) {
func tapMediaView() {
mediaTapAction?()
}
func configureWithMessage(message: Message, messageImagePreferredWidth: CGFloat, messageImagePreferredHeight: CGFloat, messageImagePreferredAspectRatio: CGFloat, mediaTapAction: MediaTapAction?) {
self.mediaTapAction = mediaTapAction
if let sender = message.fromFriend {
AvatarCache.sharedInstance.roundAvatarOfUser(sender, withRadius: YepConfig.chatCellAvatarSize() * 0.5) { roundImage in
dispatch_async(dispatch_get_main_queue()) {
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7531" systemVersion="14D131" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7520"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>

Some files were not shown because too many files have changed in this diff Show More